lino-objects-codec (Rust)
Rust implementation of the Links Notation Objects Codec - a universal serialization library to encode/decode objects to/from Links Notation format.
Installation
Add to your Cargo.toml:
[]
= "0.1"
Features
- Universal Serialization: Encode objects to Links Notation format
- Type Support: Handle all common types:
null(Null)bool(Bool)int(Int - 64-bit signed)float(Float - 64-bit, including NaN, Infinity, -Infinity)str(String)array(Array)object(Object)
- Special Float Values: Full support for NaN, Infinity, -Infinity (which are not valid JSON)
- Circular References: Detect and preserve circular references via object IDs
- Object Identity: Maintain object identity for shared references
- Readable by Default:
encode()writes indented, plain-text Links Notation; keys and values stay legible and diffable - UTF-8 Support: Full Unicode string support written as text; only values that cannot be written as text (control characters) are base64-encoded, and each is marked individually
- Simple API: Easy-to-use
encode()anddecode()functions
Quick Start
use ;
// Create an object
let data = object;
// Encode to Links Notation
let encoded = encode;
assert_eq!;
// Decode back
let decoded = decode.unwrap;
assert_eq!;
The encoded document reads as:
(
name "Alice"
age 30
active true
)
Output Formats
| Function | Output |
|---|---|
encode(value) |
Readable, indented Links Notation (the default) |
encode_with_indent(value, "\t") |
Same, with a custom indentation string |
encode_compact(value) |
The previous single-line base64 form |
encode_obfuscated(value) |
Alias of encode_compact |
decode() accepts every one of them, so files written by older versions keep
working and are rewritten in the readable form the next time they are saved.
API Reference
Types
LinoValue
The main value type that can represent any serializable value:
Helper methods:
LinoValue::object(iter)- Create an object from key-value pairsLinoValue::array(iter)- Create an array from valuesis_null(),as_bool(),as_int(),as_float(),as_str(),as_array(),as_object()- Type checking and extractionget(key)- Get a value from an object by keyget_index(index)- Get a value from an array by index
CodecError
Error type for codec operations:
Functions
encode(value: &LinoValue) -> String
Encode a value to the readable, indented Links Notation format.
let value = Int;
let encoded = encode;
assert_eq!;
encode_with_indent(value: &LinoValue, indent: &str) -> String
Same as encode(), but with a custom indentation string (the default is two spaces).
encode_compact(value: &LinoValue) -> String
Encode a value to the single-line, base64 form used before version 0.3.
let value = String;
assert_eq!;
encode_obfuscated(value: &LinoValue) -> String
Alias of encode_compact(), named after what the base64 form actually does to the text.
decode(notation: &str) -> Result<LinoValue, CodecError>
Decode Links Notation format to a value. Both the readable and the compact form are accepted.
let decoded = decode.unwrap;
assert_eq!;
let legacy = decode.unwrap;
assert_eq!;
ObjectCodec
For advanced use cases, you can create your own codec instance:
use ObjectCodec;
let mut codec = new;
let encoded = codec.encode;
let decoded = codec.decode?;
Usage Examples
Basic Types
use ;
// Null
let null = Null;
assert_eq!;
// Boolean
let bool_val = Bool;
assert_eq!;
// Integer
let int_val = Int;
assert_eq!;
// Float
let float_val = Float;
assert_eq!;
// Special floats
let inf = Float;
assert_eq!;
let nan = Float;
assert_eq!;
// Strings are quoted, not encoded
let str_val = String;
assert_eq!;
// Numbers written as strings stay strings
let numeric = String;
assert_eq!;
Collections
use ;
// Array
let array = array;
let encoded = encode;
let decoded = decode.unwrap;
assert_eq!;
// Object
let obj = object;
let encoded = encode;
let decoded = decode.unwrap;
assert_eq!;
Nested Structures
use ;
let data = object;
let encoded = encode;
let decoded = decode.unwrap;
// Access nested values
let users = decoded.get.unwrap.as_array.unwrap;
assert_eq!;
From Traits
LinoValue implements From for common Rust types:
use LinoValue;
let null: LinoValue = .into;
let bool_val: LinoValue = true.into;
let int_val: LinoValue = 42i64.into;
let float_val: LinoValue = 3.14f64.into;
let str_val: LinoValue = "hello".into;
let vec_val: LinoValue = vec!.into;
let opt_val: LinoValue = Some.into;
let none_val: LinoValue = None::.into;
How It Works
The codec encodes values using the Links Notation format.
Readable format (the default)
One ( ) construct carries both objects and arrays, at every level including
the root. Lines of the form key value make an object, bare-value lines make an
array:
(
type "RouterState"
server (
host "127.0.0.1"
port 18878
)
models (
"claude-haiku"
"claude-opus"
)
)
- Strings are double-quoted and written as text:
name "Alice" - Numbers,
true,falseandnullare bare, so types survive a round trip NaN,Infinityand-Infinityare written as such- An empty array is
(); an empty object is(+ newline +) - A value that cannot be written as text (one containing control characters) is
base64-encoded on its own and marked as
(base64 "bGluZTEKbGluZTI="); everything around it stays readable
Reading the format back requires links-notation 0.14 semantics, where a
parenthesis opens a nested indentation context.
Compact format (encode_compact)
The previous single-line form, kept for compatibility and for cases where size matters more than legibility:
- Basic types:
(int 42),(str aGVsbG8=),(bool true) - Strings are base64-encoded to handle special characters and newlines
- Arrays:
(array (int 1) (int 2) (int 3)) - Objects:
(object ((str a2V5) (int 42)) ...) - Special floats:
(float NaN),(float Infinity),(float -Infinity)
For structures with shared references or circular references, the compact form uses object IDs:
- Format:
(obj_0: array ...)or(obj_0: object ...) - References:
obj_0
decode() detects which of the two forms it is given, so previously written
files keep decoding.
Development
# Run tests
# Run example
# Build documentation
License
This project is licensed under the Unlicense - see the LICENSE file for details.