Type | rust | cljs | clj |
---|---|---|---|
NULL | ()/None | nil | nil |
TRUE/FALSE | bool | bool | bool |
INT | i64 | Number | Long |
FLOAT | f32 | Number | Float |
DOUBLE | f64 | Number | Double |
BYTES | serde_bytes::ByteBuf 0 | Int8Array | byte[] |
STRING | string | string | string |
UTF81 | string | string | string |
LIST | Vec<T> | vec | vec |
MAP | map | map | map |
SET | types::SET0 | set | set |
SYM | types::SYM2 | sym | sym |
KEY | types::KEY2 | kw | kw |
INST | types::INST3 | #inst | #inst |
UUID | types::UUID3 | #UUID | #UUID |
REGEX | types::REGEX3 | regex | regex |
URI | types::URI3 | goog.Uri | URL |
INT_ARRAY | types::IntArray(Vec<i32>)0 | Int32Array | int[] |
LONG_ARRAY | types::LongArray(Vec<i64>)0 | Array<Number>4 | long[] |
FLOAT_ARRAY | types::FloatArray(Vec<f32>)0 | Float32Array | float[] |
DOUBLE_ARRAY | types::DoubleArray(Vec<f64>)0 | Float64Array | double[] |
BOOLEAN_ARRAY | types::BooleanArray(Vec<bool>)0 | Array<bool> | bool[] |
Type | rust | cljs | clj |
---|---|---|---|
BIGINT | ??? | ??? | BigInt |
BIGDEC | ??? | ??? | BigDec |
Records | ???5 | records/TaggedObjects | records/TaggedObjects |
CHAR6 | char (utf8) | string | java char |
OBJECT_ARRAY | ??? | Obj[] | Obj[] |
Serde | Fressian | cljs | clj |
---|---|---|---|
unit | NULL | nil | nil |
bool | T/F | bool | bool |
i8 | INT | number | long |
i16 | INT | number | long |
i32 | INT | number | long |
i64 | INT | number4 | long |
u8 | INT | number | long |
u16 | INT | number | long |
u32 | INT | number | long |
u644 | INT | number | number |
f32 | FLOAT | number | float |
f64 | DOUBLE | number | double |
char6 | string | string | char |
string | STRING | string | string |
\--> | UTF81 | string | tag -> string |
[u8] | BYTES | byte-array | byte-array |
Option | value/NIL | value/NIL | value/NIL |
tuple | LIST | vec | vec |
Serde | Fressian | cljs | clj |
---|---|---|---|
seq | LIST | vec | vec |
map | MAP | map | map |
It makes sense to serialize structs and enum variants as fressian TaggedObjects
ie records or proper types. To pull this off, serde-fressian needs better support for caching. In order to better support caching, I'd like to land on a good pattern for serializing string pointers so that js interop is truly zero-copy where possible. So there are still yaks to shave.
Currently enums just serialize to the variant's value, structs serialize as maps, tuples to seqs (LIST). This is lossy, for both structs and enums because the type's name and some type information is lost. Serde offers custom attributes for altering this behavior, but right now serde-fressian mostly ignores names.
Serde | Fressian | clj(s) | Example |
---|---|---|---|
unit_struct | NULL | nil | Foo; |
newtype_variant | T | T | Foo(T) |
tuple_struct | LIST | vec | Point(x,y,z) |
struct | MAP | map | {"foo": T} |
Serde | Fressian | clj(s) | Example |
---|---|---|---|
unit_variant | string | string | Foo::Bar; |
newtype_variant | T | T | Foo::Baz(T) |
tuple_variant | LIST | vec | Foo::Point(x,y,z) |
struct_variant | MAP | map | Foo::StructVar({"foo": T}) |
Serde | Fressian | cljs | clj |
---|---|---|---|
i128 | BIGINT | TODO | bigint |
u128 | BIGINT | TODO | bigint |
All standard rust types have built-in Serialize/Deserialize impls which prevent fine grain control over serialization. For example, HashSets, BTreeSets, Slices, and Vec are all written as generic sequences and the nuance of each container is lost. This is a known source of friction in serde, and in the future there will be a way to override Serialization impls. Until then, the workaround solution is to create a 'newtype' struct enclosing your target type, which allows you to use custom serialize impls. You can use wrapper types directly, or use serde attributes (see below). This doesn't cost anything, it is just an annoyance.
The most common wrapper you'll probably need is the ByteBuf provided by the serde_bytes crate. This let's you write Vec<u8> and &[u8]
as BYTE arrays rather than generic lists.
use serde_bytes::{ByteBuf};
use serde_fressian::ser;
let bytes: Vec<u8> = vec![0,1,2];
let output = ser::to_vec(&bytes).unwrap(); //--> serialized as LIST
let bb = serde_bytes::ByteBuf::from(bytes);
let output = ser::to_vec(&bb).unwrap(); //--> serialized as BYTES
serde_fressian::set
This module provides the set::SET
wrapper for BTreeSets and set::HASHSET
for HashSets. serde_fressian
prefers BTreeSets over HashSets because the former implements Hash on the Set container itself. The same is true for BtreeMaps vs HashMaps. Hashing the container itself is required for implementing serde_fressian::value
(see below) because it enables using the containers themselves as keys (..or set values), which may show up in that crazy clojure data.
#[macro_use]
extern crate maplit; // provides map & set literals
use std::collections::{BTreeSet,HashSet};
use serde_fressian::set::{SET, HASHSET};
use serde_fressian::ser;
let btreeset: BTreeSet<i64> = btreeset!{0,1,2,3};
let output = ser::to_vec(&btreeset); //--> serialized as LIST; [0 1 2 3]
let wrapped_btreeset: SET<i64> = SET::from(btreeset);
let output = ser::to_vec(&wrapped_btreeset); //--> serialized as SET; #{0 1 2 3}
// SET derives hash from its btreeset, so it can be stored in a hashset if we want
// but we could not do the other way around.
let hashset: HashSet<SET<i64>> = hashset!{wrapped_btreeset};
let output = ser::to_vec(&hashset); //--> serialized as LIST; [#{0 1 2 3}]
let wrapped_hashset: HASHSET<SET<i64>> = HASHSET::from(hashset);
let output = ser::to_vec(&wrapped_hashset); //--> serialized as SET; #{#{0 1 2 3}}
serde_fressian::typed_arrays
This module provides additional wrappers for fressian's typed arrays:
use serde_fressian::ser;
use serde_fressian::typed_arrays::{DoubleArray};
let v: Vec<f64> = vec![-2.0, -1.0, 0.0, 1.0, 2.0];
let output = ser::to_vec(&v).unwrap(); //--> serialized as LIST
let da: DoubleArray = DoubleArray::from_vec(v);
let output = ser::to_vec(&da).unwrap(); //--> serialized as DOUBLE_ARRAY
As you would expect, symbols and keywords do not have analogous rust types. The serde_fressian::sym::{SYM}
and serde_fressian::key::{KEY}
types are provided for compatibility. They are both tuple structs composed of an Option<String>
namespace and a String
Name. They have no other built-in functionality outside of lossless serialization.
With the expectation that they will be less commonly used, the remaining types default to newtypes over primitives in the interest of keeping binaries small. You can use compiler flags to enable extra functionality provided by external crates:
serde_fressian::regex::{REGEX}
String
use_regex_crate
feature to enable the external regex crateserde_fressian::uri::{URI}
String
use_url_crate
feature to enable the external url crateserde_fressian::uuid::{UUID}
ByteBuf
use_uuid_crate
feature to enable the external uuid crateserde_fressian::inst::{INST}
i64
You can use serde attributes to use custom serialize/deserialize impls produced by serde-derive. For example, this is from serde_bytes
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_bytes;
#[derive(Serialize)]
struct Efficient<'a> {
#[serde(with = "serde_bytes")]
bytes: &'a [u8],
#[serde(with = "serde_bytes")]
byte_buf: Vec<u8>,
}
#[derive(Serialize, Deserialize)]
struct Packet {
#[serde(with = "serde_bytes")]
payload: Vec<u8>,
}
serde_fressian::value::Value
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close