structio 0.4.0
#[derive(Structio)] behind an optional feature, a Value tree, and a late enum tag. One breaking change: a raw identifier's r# is no longer part of its key.
[dependencies]
structio = "0.4"
# The derive is off by default:
structio = { version = "0.4", features = ["derive"] }Changed
-
A raw identifier's
r#is no longer part of its key. A field or variant writtenr#typehad the keyr#type, because that is whatstringify!hands the macro. It is nowtype, before any case rule runs, since the prefix is how Rust spells a name that collides with a keyword rather than part of the name:r#typeis how you write a field for a"type"key. Both formats, fields and variants, derived and declared. An explicit"r#type" => fieldis a literal and is unchanged. Breaking for a declaration with a raw identifier and no explicit key, which now reads and writes a different key. -
An internally tagged enum's tag no longer has to come first.
tagged_enum!(.. as tag "kind")used to refuse an object whose first member was not the tag withExpectedTag, which refused every document from a sorted-key writer the moment a member sorted before the tag. The reader now steps over the members before the tag, dispatches on it, reads the members after it, and then reads the ones it stepped over, nesting as deep as the payloads do. A tag that is first still costs one pass; the members before a late tag are walked twice, and a key on both sides of the tag keeps its earlier value. Required-field and unknown-key rules apply to the deferred members as to any other. An object with no tag at all is stillExpectedTag, reported against its first key.
Added
#[derive(Structio)], behind thederivefeature. A front end toobject!,array!,unit_enum!andtagged_enum!: it reads the type and emits the declaration, so a derived type and a declared type are the same impls.rename_all,tag,array,element,json,beveandcrateon the type;rename,skip,requiredandwithon a field;renameon a variant. Generics and their bounds are read off the type. The feature is off by default and the derive crate has no dependencies. docs/derive.md has the rest, including what later stages add.- BEVE containers reserve on the wire count.
Reader::read_seq_countedandread_map_countedhand the element count to the caller before the first element, clipped to what the input could hold, andbeve::cautious::<T>clips it again to a megabyte ofT.Vec,VecDeque,HashMapandHashSet, adapted or not, reserve once instead of doubling up; a hostile count can waste at most that megabyte. Value, a tree for a value with no declared type. Null, bool, number, string, array, object, withget,pointer/pointer_mut, theas_*/is_*accessors,Index/IndexMutby key or position, and thevalue!macro to build one. It reads and writes through both formats like any other type, so it can be a field of anobject!declaration or a whole document; a BEVE typed array, complex run or matrix reads into the same shapebeve_to_jsonwrites.Numberkeeps whether it was an unsigned integer, a negative integer or a float, and writes a whole-valued float as1.0so the kind survives a trip through text.to_valueandfrom_valuemove a declared type in and out, through JSON text. This is for the value nothing decodes, a register tree walked by path or a body forwarded unread, not a substitute for a declared type, and the crate's stance on that is unchanged.
Upgrading
The break is narrow. A declaration with a raw identifier and no explicit key changes the key it reads and writes: a field written r#type was keyed r#type and is now keyed type. Nothing else about a 0.3.2 declaration changes its bytes. If you were working around the old behaviour with "r#type" => r#type, that explicit key still means exactly what it says and will keep the old wire format.
The derive feature is additive and off by default, so a crate that does not enable it builds structio with no dependencies and no proc-macro, as before.