Rust
How Rust types map to STYX syntax. Examples use facet derives.
Implicit root object
STYX documents are implicitly objects. When parsing, the top-level content is wrapped in an implicit root object. This means you cannot parse a bare tagged value directly into an enum — you need a wrapper struct.
// This struct wraps the enum value
# [ derive ( Facet )]
struct Doc {
status : Status ,
}
# [ derive ( Facet )]
enum Status {
Ok ,
Pending ,
}
// Parse: "status @ok"
let doc: Doc = from_str ( "status @ok" ) ?;
assert_eq! ( doc. status , Status :: Ok );
status @ok
If you need to parse a document where the root is the tagged value, use an explicit root object:
{@ @ok}
This creates an object with a unit key (@) whose value is the @ok tag.
Structs
# [ derive ( Facet )]
struct Server {
host : String ,
port : u16 ,
}
host localhost
port 8080
Optional fields (absent)
# [ derive ( Facet )]
struct Config {
timeout : Option < Duration >,
}
let c = Config { timeout : None };
{ }
Optional fields (present)
# [ derive ( Facet )]
struct Config {
timeout : Option < Duration >,
}
let c = Config {
timeout : Some ( Duration :: from_secs ( 30 )),
};
{timeout 30s}
Sequences
# [ derive ( Facet )]
struct Doc {
tags : Vec < String >,
}
let d = Doc {
tags : vec! [
"web" . into (),
"prod" . into (),
],
};
tags (web prod)
Maps
# [ derive ( Facet )]
struct Doc {
env : HashMap < String , String >,
}
let d = Doc {
env : HashMap :: from ([
( "HOME" . into (), "/home/user" . into ()),
( "PATH" . into (), "/usr/bin" . into ()),
]),
};
env {
HOME /home/user
PATH /usr/bin
}
Nested structs
# [ derive ( Facet )]
struct Server {
host : String ,
tls : TlsConfig ,
}
# [ derive ( Facet )]
struct TlsConfig {
cert : String ,
key : String ,
}
host localhost
tls {
cert /path/cert.pem
key /path/key.pem
}
Flatten
# [ derive ( Facet )]
struct User {
name : String ,
email : String ,
}
# [ derive ( Facet )]
struct Admin {
# [ facet ( flatten )]
user : User ,
perms : Vec < String >,
}
name Alice
email alice@example.com
perms (read write)
Unit enum variants
Enum variants with no payload use implicit unit (@variant is shorthand for @variant@).
# [ derive ( Facet )]
struct Doc {
status : Status ,
}
# [ derive ( Facet )]
enum Status {
Ok ,
Pending ,
}
let d = Doc { status : Status :: Ok };
status @ok
Struct enum variants
Struct variants use @variant{...} syntax with the variant's fields inside.
# [ derive ( Facet )]
struct Doc {
result : MyResult ,
}
# [ derive ( Facet )]
enum MyResult {
Err { message : String },
}
let d = Doc {
result : MyResult :: Err {
message : "timeout" . into (),
},
};
result @err{message "timeout"}
Tuple enum variants
Tuple variants use @variant(...) syntax. Note: parentheses create a sequence, so each tuple element is a sequence element.
# [ derive ( Facet )]
struct Doc {
color : Color ,
}
# [ derive ( Facet )]
enum Color {
Rgb ( u8 , u8 , u8 ),
}
let d = Doc {
color : Color :: Rgb ( 255 , 128 , 0 ),
};
color @rgb(255 128 0)
Catch-all variants with #[facet(other)]
For extensible enums, mark a variant with #[facet(other)] to catch unknown tags.
Use #[facet(tag)] and #[facet(content)] on fields to capture the tag name and payload.
# [ derive ( Facet )]
struct Doc {
schema : Schema ,
}
# [ derive ( Facet )]
enum Schema {
// Known variant
Object { fields : Vec < String > },
// Catch-all for unknown type references
# [ facet ( other )]
Type {
# [ facet ( tag )]
name : String ,
},
}
// @string doesn't match any known variant,
// so it's captured as Type { name: "string" }
let d: Doc = from_str ( "schema @string" ) ?;
schema @string
Durations
use std:: time:: Duration ;
let d = Duration :: from_secs ( 30 );
30s
Bytes (hex)
let bytes: Vec < u8 > = vec! [
0xde , 0xad , 0xbe , 0xef ,
];
deadbeef