In this page
std > io
Input/output module providing file operations, data serialization, network communication, and email functionality for GreyCat applications.
Writers & Readers
All reader types implement position tracking and support streaming operations for memory-efficient processing of large files. Writers support both append and overwrite modes. CSV operations include advanced analysis capabilities for automatic type inference and code generation.
GcbWriter / GcbReader
Binary format using GreyCat’s ABI encoding for efficient serialization of any GreyCat type.
// Write binary data
var writer = GcbWriter<MyType> { path: "/path/to/data.gcb" };
writer.write(my_object);
writer.flush();
// Read binary data back
var reader = GcbReader<MyType> { path: "/path/to/data.gcb" };
while (reader.can_read()) {
var obj = reader.read();
Assert::isNotNull(obj);
}
GcxWriter / GcxReader
GreyCat exchange format (.gcx): a binary stream of values that does not depend on the ABI, so a program whose types changed, or a tool outside GreyCat, can still read it. Values are tagged like GCB, objects carry their field names, and type, field and enum entry names are written once, in a dictionary at the end of the file, by close(). The file is readable only once closed.
var writer = GcxWriter<Person> { path: "people.gcx" };
writer.write(Person { name: "Ada", age: 36 });
writer.close();
var reader = GcxReader<Person> { path: "people.gcx" };
while (reader.can_read()) {
var p = reader.read();
Assert::equals(p.name, "Ada");
}
GcxWriter { path, append: true } keeps the values of an existing closed file and writes after them. close() is not optional: a file never closed has no dictionary, and the reader rejects it. A writer whose task was suspended (await) refuses further writes instead of starting the file over; GcxReader resumes at its pos.
Reading into a program whose types changed: a field the type no longer has is skipped; a field missing from the file reads as null, and is an error when the field is not nullable; an unknown type, enum entry, field or function value is an error naming it.
Values nest at most 512 objects or containers deep: the writer refuses a deeper value, as the reader does.
Byte layout
header "GCX\0" (4 bytes), u16 format version = 1
values encoded values, one after another
dictionary vu name count, then per name: vu byte length, UTF-8 bytes
trailer u64 byte length of the dictionary, "GCXE" (4 bytes)
Fixed-width integers are little-endian. Name ids are positions in the dictionary, from 0. vu is an unsigned varint: 7 bits per byte, low bits first, the high bit set when another byte follows; a ninth byte, if reached, carries the top 8 bits unmasked. vi is zig-zag mapped ((v << 1) ^ (v >> 63)), then vu.
Every value starts with a one-byte tag:
| tag | value | body |
|---|---|---|
| 0 | null | none |
| 1 | false | none |
| 2 | true | none |
| 3 | int | vi |
| 4 | float | 8 bytes, IEEE 754 binary64 |
| 5 | char | vu, the code point |
| 6 | time | vi, microseconds since the epoch |
| 7 | duration | vi, microseconds |
| 8 | geo | 8 bytes, GreyCat’s 64-bit geo code |
| 9 | String | vu byte length, UTF-8 bytes |
| 10 | Buffer | vu byte length, bytes |
| 11 | node | vu node reference |
| 12 | nodeTime | vu node reference |
| 13 | nodeIndex | vu node reference |
| 14 | nodeList | vu node reference |
| 15 | nodeGeo | vu node reference |
| 16 | enum | vu type name, vu entry name |
| 17 | object | vu type name, vu field count, then per field: vu field name, value |
| 18 | Array | vu type name, vu element count, element block |
| 19 | Map | vu type name, vu entry count, then per entry: key value, value |
| 20 | Table | vu type name, vu rows, vu columns, then one element block of rows elements per column |
| 21 | Tensor | vu TensorType entry name, vu dimension count, vi per dimension, raw little-endian data |
| 22 | type | vu type name |
| 23 | field | vu type name, vu field name |
| 24 | function | vu module name, vu (type name + 1, or 0 for a module function), vu function name |
A type name is the type’s full name, specialization included: project::Sensor, core::Array<core::int>. A function’s type name is the type’s own name (Sensor), its module given apart. An element block holds one tag followed by the bare bodies when every element is an int, float, char, time, duration, geo or one node kind; otherwise the byte 0xFF followed by every element as a tagged value. An object writes only its non-null fields. Node references are written raw: they mean something only in the store that wrote them.
TextWriter / TextReader
UTF-8 text file operations with line-based I/O.
// Write text lines
var writer = TextWriter<String> { path: "/path/to/output.txt" };
writer.writeln("First line");
writer.writeln("Second line");
writer.flush();
// Read text lines
var reader = TextReader { path: "/path/to/output.txt" };
Assert::equals(reader.read(), "First line");
Assert::equals(reader.read(), "Second line");
Assert::isFalse(reader.can_read());
JsonWriter / JsonReader
JSON serialization supporting both single objects and NDJSON (newline-delimited JSON) streams.
// Write JSON objects
var writer = JsonWriter<Person> { path: "/path/to/people.json" };
writer.writeln(person1); // Each call writes one JSON object per line
writer.writeln(person2);
writer.flush();
// Read JSON stream
var reader = JsonReader<Person> { path: "/path/to/people.json" };
var first_person = reader.read();
Assert::equals(first_person.name, "John");
// Parse JSON strings directly
var parsed = Json<Person>::parse("{\"name\":\"Alice\",\"age\":30}");
Assert::equals(parsed.name, "Alice");
CsvWriter / CsvReader
CSV file operations with automatic header generation and configurable formatting.
// Configure CSV format
var format = CsvFormat {
header_lines: 1,
separator: ',',
string_delimiter: '"'
};
// Write structured data as CSV
var writer = CsvWriter<Employee> { path: "/path/to/employees.csv", format: format };
writer.write(employee1); // Headers written automatically on first write
writer.write(employee2);
writer.flush();
// Read CSV with type validation
var reader = CsvReader<Employee> { path: "/path/to/employees.csv", format: format };
while (reader.can_read()) {
var emp = reader.read();
Assert::isNotNull(emp.name);
}
// Re-use reader for multiple files
reader.set_path("/path/to/other_employees.csv");
Assert::isTrue(reader.can_read());
CSV Analysis & Code Generation
Csv
Static utility for analyzing CSV files and generating GreyCat types.
// Analyze CSV structure
var config = CsvAnalysisConfig {
row_limit: 1000,
enumerable_limit: 50
};
var files = Array<File> {File::open("/path/to/sales.csv")!!};
var stats = Csv::analyze(files, config);
// Generate GreyCat types based on analysis
var type_definitions = Csv::generate(stats);
Assert::isTrue(type_definitions.contains("type"));
// Sample data for preview
var reader = CsvReader<any> { path: "/path/to/sales.csv" };
var sample_table = Csv::sample(reader, 100);
Assert::equals(sample_table.rows(), 100);
File System Operations
File
Comprehensive file system utilities for file and directory management.
// File discovery and metadata
var csv_files = File::ls("/path/to/data", ".csv", true); // Recursive search
Assert::isTrue(csv_files.size() > 0);
var file = File::open("/path/to/important.txt")!!;
Assert::isFalse(file.isDir());
Assert::equals(file.extension()!!, "txt");
Assert::isNotNull(file.sha256()!!);
// File operations
Assert::isTrue(File::copy("/path/to/source.txt", "/path/to/dest.txt"));
Assert::isTrue(File::rename("/path/to/old.txt", "/path/to/new.txt"));
Assert::isTrue(File::delete("/path/to/unwanted.txt"));
Assert::isTrue(File::mkdir("/path/to/directory"));
// Working directories
var base_dir = File::baseDir();
var user_dir = File::userDir();
var work_dir = File::workingDir();
Assert::isNotNull(base_dir);
FileWalker
Iterator for traversing file system hierarchies.
// Walk through directory structure
var walker = FileWalker { path: "." };
var file_count = 0;
while (!walker.isEmpty()) {
var file = walker.next();
if (file != null && !file.isDir()) {
file_count++;
}
}
println("file count = ${file_count}");
Network & Web
Url
URL parsing and manipulation utility.
// Parse URL components
var url = Url::parse("https://api.example.com:8080/users?active=true#section1");
Assert::equals(url.protocol, "https");
Assert::equals(url.host, "api.example.com");
Assert::equals(url.port, 8080);
Assert::equals(url.path, "/users");
Assert::equals(url.params?.get("active"), "true");
Assert::equals(url.hash, "section1");
Email & Communication
Email & Smtp
Email composition and SMTP delivery.
// Configure SMTP server
var smtp = Smtp {
host: "smtp.example.com",
port: 587,
mode: SmtpMode::starttls,
authenticate: SmtpAuth::plain,
user: "sender@example.com",
pass: "password123"
};
// Compose and send email
var email = Email {
from: "sender@example.com",
to: ["recipient@example.com"],
cc: ["cc@example.com"],
subject: "Test Email",
body: "<h1>Hello World</h1>",
body_is_html: true
};
// Send email (would throw exception on failure)
smtp.send(email);