| Crates.io | cio |
| lib.rs | cio |
| version | 0.5.1 |
| created_at | 2025-04-29 20:40:16.361493+00 |
| updated_at | 2025-05-25 20:20:37.339484+00 |
| description | CIO provides two powerful procedural macros (`println!` and `input!`) that enhance console I/O operations in Rust, bringing Python-like convenience to Rust's type-safe environment. |
| homepage | https://github.com/gerarddubard/cio |
| repository | https://github.com/gerarddubard/cio |
| max_upload_size | |
| id | 1654040 |
| size | 145,341 |
CIO brings Python-like simplicity to Rust console operations with powerful procedural macros that enhance println! and provide type-safe input!. Experience advanced table formatting, ANSI colors, mathematical matrices, and seamless JSON integration.
@(color, style) syntax:m and :d formatsinput! macro$(...)serde_json integration:t, :m, :d, :a, :c, :j[dependencies]
cio = "0.5.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
use cio::{println, input};
use serde_json::json;
fn main() {
// Type-safe input with automatic parsing
let name: String = input!("Your name: ");
let age: i32 = input!("Your age: ");
// Rich colored output
println!("Hello, @(green, bold){name}@()! You are @(yellow){age}@() years old.");
// Advanced table formatting
let data = json!({"France": "Paris", "Germany": "Berlin"});
println!("Capitals: {data:t(Country, Capital)}");
}
input!The input! macro provides automatic type parsing with elegant error handling:
use cio::input;
// Basic types with automatic parsing
let name: String = input!("Your @(green,italic)first name@(): ");
let age: i32 = input!("Your @(yellow)age@(): ");
let height: f64 = input!("Your @(blue)height@() (in meters): ");
let married: bool = input!("Are you @(magenta)married@()? (true/false): ");
let favorite_letter: char = input!("What is your @(cyan,italic)favorite letter@()? ");
Features:
@(color) syntax in input promptsprintln! with ANSI ColorsUse @(color, style) for rich terminal output:
use cio::println;
// Basic colors
println!("@(red)Error:@() Something went wrong");
println!("@(green,bold)Success!@() Operation completed");
// Multiple styles
println!("@(blue,bold,italic)Important Notice@() - Please read carefully");
// Reset with @()
println!("Normal text @(yellow)highlighted@() back to normal");
Standard Colors: black, red, green, yellow, blue, magenta, cyan, white
Bright Colors: bright_red, bright_green, bright_blue, bright_cyan, bright_magenta, bright_yellow, bright_white, bright_black
Styles: bold, italic, underline, dimmed, blink, reversed, hidden, strikethrough
let color_style = "bright_blue,bold,italic";
let temp = 18.7;
println!("@({color_style}){temp:.1}Β°C@()");
$(...)Control output flow with dynamic separators:
use cio::println;
// Progress indicators without newlines
for i in 1..10 {
println!("@(yellow){i}$( β )"); // Custom separator
}
println!("@(yellow)10"); // Final item with newline
// Output: 1 β 2 β 3 β 4 β 5 β 6 β 7 β 8 β 9 β 10
Separator Options:
$( β ) - Custom separator string$(\n) - Explicit newline$(sep_variable) - Dynamic separator from variable:t)CIO automatically detects data structure and creates professional tables:
use cio::println;
use serde_json::json;
// JSON object β Key-value table
let capitals = json!({
"France": "Paris",
"Italy": "Rome",
"Germany": "Berlin",
"Spain": "Madrid"
});
println!("European Capitals: {capitals:t(Country, Capital)}");
Output:
βββββββββββ¬ββββββββββ
β Country β Capital β
βββββββββββΌββββββββββ€
β France β Paris β
βββββββββββΌββββββββββ€
β Germany β Berlin β
βββββββββββΌββββββββββ€
β Italy β Rome β
βββββββββββΌββββββββββ€
β Spain β Madrid β
βββββββββββ΄ββββββββββ
CIO handles deeply nested JSON with hierarchical headers:
let class_grades = json!({
"6A": {
"FranΓ§ais": [16.0, 13.0, 18.0, 15.0, 17.0],
"MathΓ©matiques": [15.0, 11.0, 16.0, 14.0, 15.0]
},
"6B": {
"FranΓ§ais": [14.0, 12.0, 15.0, 13.0, 14.0],
"MathΓ©matiques": [12.0, 11.0, 14.0, 13.0, 11.0]
}
});
println!("Class Grades: {class_grades:t}");
Output:
ββββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β 6A β 6B β
βββββββββββββββββΌβββββββ¬βββββββ¬βββββββ¬βββββββ¬βββββββΌβββββββ¬βββββββ¬βββββββ¬βββββββ¬βββββββ€
β FranΓ§ais β 16.0 β 13.0 β 18.0 β 15.0 β 17.0 β 14.0 β 12.0 β 15.0 β 13.0 β 14.0 β
βββββββββββββββββΌβββββββΌβββββββΌβββββββΌβββββββΌβββββββΌβββββββΌβββββββΌβββββββΌβββββββΌβββββββ€
β MathΓ©matiques β 15.0 β 11.0 β 16.0 β 14.0 β 15.0 β 12.0 β 11.0 β 14.0 β 13.0 β 11.0 β
βββββββββββββββββ΄βββββββ΄βββββββ΄βββββββ΄βββββββ΄βββββββ΄βββββββ΄βββββββ΄βββββββ΄βββββββ΄βββββββ
CIO works seamlessly with standard Rust collections:
use std::collections::{HashMap, BTreeMap, HashSet, VecDeque};
// HashMap
let mut capitals = HashMap::new();
capitals.insert("France", "Paris");
capitals.insert("Germany", "Berlin");
println!("HashMap Display: {capitals:t(Country, Capital)}");
// BTreeMap (automatically sorted)
let mut btree_map = BTreeMap::new();
btree_map.insert("C", 3);
btree_map.insert("A", 1);
btree_map.insert("B", 2);
println!("BTreeMap: {btree_map:t(Key, Value)}");
// HashSet
let mut hash_set = HashSet::new();
hash_set.insert("apple");
hash_set.insert("banana");
println!("HashSet: {hash_set:t}");
// VecDeque
let mut vecdeque = VecDeque::new();
vecdeque.push_back("Second");
vecdeque.push_front("First");
println!("VecDeque: {vecdeque:t}");
:m)Display matrices with proper mathematical notation:
let matrix_2d = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
println!("3x3 Matrix: {matrix_2d:m}");
Output:
β 1 2 3 β
β 4 5 6 β
β 7 8 9 β
:d)Display determinants with vertical bars:
let matrix_small = vec![vec![4, 3], vec![2, 1]];
println!("Determinant: {matrix_small:d}");
Output:
β 4 3 β
β 2 1 β
let matrix = vec![vec![4, 3], vec![2, 1]];
let sum: i32 = matrix.iter().flatten().sum();
println!("Matrix: {matrix:m}");
println!("Sum of all elements: @(bright_green){sum}");
| Format | Description | Best For |
|---|---|---|
:t |
Smart table formatting | Data display, JSON objects, collections |
:t(Col1, Col2) |
Table with custom headers | Structured data with specific column names |
:m |
Mathematical matrix notation | 2D arrays, mathematical computations |
:d |
Determinant notation | Square matrices, mathematical expressions |
:a |
Array format with indentation | Nested data structures, debug output |
:c |
Compact single-line format | Dense data, debugging |
:j |
JSON pretty-print format | Complex objects, configuration files |
let demo_matrix = json!([[1, 2, 3], [4, 5, 6]]);
let demo_native = vec![vec![1, 2, 3], vec![4, 5, 6]];
println!("Standard: {demo_matrix}");
println!("Compact: {demo_matrix:c}");
println!("Array: {demo_matrix:a}");
println!("Matrix: {demo_native:m}");
println!("Table: {demo_matrix:t}");
use cio::println;
use std::collections::HashMap;
let dataset = vec![
("Alice", 28, 75.5, "Marketing"),
("Bob", 35, 82.3, "Engineering"),
("Charlie", 42, 91.0, "Management"),
];
// Advanced data analysis with turbofish
let mut dept_count = HashMap::<&str, i32>::new();
let mut dept_ages = HashMap::<&str, Vec<i32>>::new();
for (_name, age, _weight, dept) in &dataset {
*dept_count.entry(*dept).or_insert(0) += 1;
dept_ages.entry(*dept).or_insert_with(Vec::<i32>::new).push(*age);
}
println!("@(blue,bold)Department Statistics:");
for (dept, count) in &dept_count {
let ages = &dept_ages[dept];
let avg_age = ages.iter().sum::<i32>() as f64 / ages.len() as f64;
println!("@(cyan){dept}@(): {count} people, avg age: {avg_age:.1}");
}
let sales_data = vec![
("Q1", "North", "Software", 12000.0, 150),
("Q1", "South", "Hardware", 15000.0, 75),
("Q2", "North", "Software", 14500.0, 180),
];
// Multi-dimensional analysis
let quarterly_summary: HashMap<&str, HashMap<&str, HashMap<&str, (f64, i32)>>> =
sales_data.iter()
.fold(
HashMap::<&str, HashMap<&str, HashMap<&str, (f64, i32)>>>::new(),
|mut acc, (quarter, region, product, revenue, units)| {
let quarter_entry = acc.entry(*quarter)
.or_insert_with(HashMap::<&str, HashMap<&str, (f64, i32)>>::new);
let region_entry = quarter_entry.entry(*region)
.or_insert_with(HashMap::<&str, (f64, i32)>::new);
let product_entry = region_entry.entry(*product).or_insert((0.0, 0));
product_entry.0 += *revenue;
product_entry.1 += *units;
acc
}
);
println!("@(blue,bold)Quarterly Summary:");
for (quarter, regions) in &quarterly_summary {
println!("@(cyan){quarter}:@()");
for (region, products) in regions {
println!(" @(yellow){region}:@()");
for (product, (revenue, units)) in products {
println!(" {product}: ${revenue:.0} revenue, {units} units");
}
}
}
Use JSON (json!) for:
// Perfect for JSON
let config = json!({
"database": {
"host": "localhost",
"port": 5432,
"name": "myapp"
}
});
println!("Configuration: {config:t}");
Use Native Collections for:
.iter(), .get(), .insert()// Perfect for Native
let mut sales = HashMap::new();
sales.insert("Q1", 50000.0);
sales.insert("Q2", 75000.0);
let total: f64 = sales.values().sum(); // Native operations
println!("Sales Analysis: {sales:t(Quarter, Revenue)}");
println!("Total: @(green,bold)${total:.0}@()");
// System messages
println!("@(red,bold)Error:@() Connection failed");
println!("@(yellow,bold)Warning:@() Low disk space");
println!("@(green,bold)Success:@() File saved");
println!("@(blue,bold)Info:@() Processing...");
// Data highlighting
println!("Temperature: @(bright_red){temp:.1}Β°C@() (above normal)");
println!("Status: @(bright_green,bold)ACTIVE@()");
// Progress indicators
for i in 1..=5 {
println!("Step {i}: @(cyan)Processing@()$( β )");
}
let first_name = "John";
let last_name = "Doe";
let age = 30;
let height = 1.85;
// Direct expressions in placeholders
println!("Age in months: @(yellow){age * 12}");
println!("Height in cm: @(blue){height * 100.0:.0}");
println!("Full name: @(green,bold){first_name} {last_name.to_uppercase()}@()");
// Complex expressions
let letter = 'A';
let category = if letter.is_alphabetic() { "letter" } else { "symbol" };
println!("Character '@(magenta){letter}@()' is a {category}");
// Input macro handles errors gracefully
let number: i32 = input!("Enter a number: "); // Retries automatically on invalid input
// Println macro provides safe defaults
let data = problematic_data;
println!("Data: {data:t}"); // Falls back to Debug format if JSON fails
All examples from this README are available in a complete demonstration:
cargo new cio_demo
cd cio_demo
# Add the complete main.rs example from the repository
cargo run
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
This project is licensed under the MIT License - see the LICENSE file for details.