Wado
<!-- Auto-generated by: wado doc -f markdown core:serde --> <!-- Do not edit this file directly. -->

core:serde

Serialization and deserialization framework.

Provides format-agnostic Serialize and Deserialize traits with a 17-method data model optimized for JSON and CBOR. Format implementations (e.g., core:json) implement Serializer and Deserializer to support specific wire formats.

use { Serialize, Deserialize, SerializeError, DeserializeError } from "core:serde";

Deriving Serialize / Deserialize

impl Serialize for T; / impl Deserialize for T; (empty body — the compiler fills it in) is optional: a T: Serialize bound is satisfied structurally once every field or case of T implements the trait — how an anonymous struct, which has no name for a marker, becomes serializable. Write the marker to force the impl with no bound present, or alongside #[serde(...)] customization.

struct Point { x: i32, y: i32 }               // no marker needed
let json = to_string(&Point { x: 1, y: 2 });  // Ok("{\"x\":1,\"y\":2}")

Field naming on the wire

By default the wire-form key is the Wado source field name verbatim (identity): user_name stays "user_name", userId stays "userId". The field name as written is the single source of truth. Override per struct with #[serde(rename_all = "...")], or per field with #[serde(rename = "...")] (which takes precedence).

rename_all strategies: "camelCase", "snake_case", "PascalCase", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE".

The same rename / rename_all overrides apply to enum and variant case names (default: the PascalCase name verbatim), e.g. #[serde(rename_all = "kebab-case")] makes AddRemote serialize as "add-remote".

// Default — wire keys are the field names as written
struct User {
    user_name: String,        // wire key: "user_name"
    account_id: i64,          // wire key: "account_id"
}

// Per-struct convention (e.g. camelCase for a JS-facing API)
#[serde(rename_all = "camelCase")]
struct Event {
    created_at: String,       // wire key: "createdAt"
    event_type: String,       // wire key: "eventType"
}

// Per-field override (wins over rename_all)
#[serde(rename_all = "kebab-case")]
struct Header {
    content_type: String,     // wire key: "content-type"
    #[serde(rename = "X-Trace-Id")]
    trace_id: String,         // wire key: "X-Trace-Id"
}

Missing fields on deserialization

A missing required field produces DeserializeError with kind MissingField. A field with a default value (f: T = expr) is optional: when absent it falls back to that expression. This is the single mechanism for an optional field — for a zero-value fallback, write the zero literal (= 0, = "", = false, = [], = null).

struct Config {
    host: String,             // required - error if missing
    port: i32 = 0,            // missing -> 0
    timeout: i32 = 30,        // missing -> 30
}
impl Deserialize for Config;

// {"host":"localhost"}
//   -> Config { host: "localhost", port: 0, timeout: 30 }

Traits

pub trait SerializeSeq

fn element<T: Serialize>(&mut self, value: &T) -> Result<(), SerializeError>

fn end(&mut self) -> Result<(), SerializeError>

pub trait SerializeMap

fn key<T: Serialize>(&mut self, key: &T) -> Result<(), SerializeError>

fn value<T: Serialize>(&mut self, value: &T) -> Result<(), SerializeError>

fn end(&mut self) -> Result<(), SerializeError>

pub trait SerializeStruct

fn field<T: Serialize>(&mut self, name: &String, value: &T) -> Result<(), SerializeError>

fn end(&mut self) -> Result<(), SerializeError>

pub trait SerializeVariant

fn payload<T: Serialize>(&mut self, value: &T) -> Result<(), SerializeError>

fn end(&mut self) -> Result<(), SerializeError>

pub trait Serializer

fn serialize_i32(&mut self, v: i32) -> Result<(), SerializeError>

fn serialize_i64(&mut self, v: i64) -> Result<(), SerializeError>

fn serialize_u32(&mut self, v: u32) -> Result<(), SerializeError>

fn serialize_u64(&mut self, v: u64) -> Result<(), SerializeError>

fn serialize_i128(&mut self, v: i128) -> Result<(), SerializeError>

fn serialize_u128(&mut self, v: u128) -> Result<(), SerializeError>

fn serialize_f32(&mut self, v: f32) -> Result<(), SerializeError>

fn serialize_f64(&mut self, v: f64) -> Result<(), SerializeError>

fn serialize_bool(&mut self, v: bool) -> Result<(), SerializeError>

fn serialize_char(&mut self, v: char) -> Result<(), SerializeError>

fn serialize_string(&mut self, v: &String) -> Result<(), SerializeError>

fn serialize_tag(&mut self, _tag: u64) -> Result<(), SerializeError>

Tag the next value with a CBOR semantic tag (major type 6, RFC 8949 §3.4). Formats with no tag concept ignore it; the default no-op means only tag-aware serializers (CBOR) need to implement it.

fn serialize_bytes(&mut self, v: ByteSlice) -> Result<(), SerializeError>

Serialize a byte string. Self-describing binary formats (CBOR) emit a native byte string; JSON emits base64. The default falls back to a sequence of u8 (the historical List<u8> behaviour), so a format with no distinct byte-string form keeps working unchanged.

fn serialize_null(&mut self) -> Result<(), SerializeError>

fn begin_seq(&mut self, len: i32) -> Result<Self::SeqSerializer, SerializeError> with stores[self]

fn begin_map(&mut self, len: i32) -> Result<Self::MapSerializer, SerializeError> with stores[self]

fn begin_struct(&mut self, name: &String, fields: i32) -> Result<Self::StructSerializer, SerializeError> with stores[self]

fn serialize_unit_variant(&mut self, type_name: &String, variant_name: &String, disc: i32) -> Result<(), SerializeError>

fn begin_variant(&mut self, type_name: &String, variant_name: &String, disc: i32) -> Result<Self::VariantSerializer, SerializeError> with stores[self]

pub trait Serialize

fn serialize<S: Serializer>(&self, s: &mut S) -> Result<(), SerializeError>

pub trait DeserializeSeq

fn next_element<T: Deserialize>(&mut self) -> Result<Option<T>, DeserializeError>

fn end(&mut self) -> Result<(), DeserializeError>

pub trait DeserializeMap

fn next_key_string(&mut self) -> Result<Option<String>, DeserializeError>

fn next_value<V: Deserialize>(&mut self) -> Result<V, DeserializeError>

fn end(&mut self) -> Result<(), DeserializeError>

pub trait FieldSchema

Static, per-type, format-agnostic field-name → index mapping.

The struct-deserialize synthesiser implements FieldSchema for every deserializable struct, generating a lookup that byte-compares the wire key against the wire-form field names. Self-describing formats invoke it from DeserializeStruct::next_field with the key's bytes; non-self-describing formats ignore the schema and stay positional.

The key is a borrowed byte view (ArraySlice<u8>, i.e. ByteSlice), not a String: deserializer input is bytes (UTF-8 for JSON, a byte string for CBOR), so a bytes key avoids a String round-trip and is shared identically by every format.

lookup is a static method resolved at monomorphization, so the call is direct and inlinable — no closure value, no per-decode allocation.

A field marked #[serde(positional)] is ordinal, not nominal: lookup omits it (it is never matched by name) and positional_at enumerates the positional fields in declaration order. Name-only and sequence-only formats ignore positional_at and stay backward compatible; core:args consults it to bind bare tokens to positional fields.

fn lookup(key: ArraySlice<u8>) -> Option<i32>

fn positional_at(rank: i32) -> Option<i32>

Field index of the rank-th #[serde(positional)] field (in declaration order), or null when rank is out of range. Returns null for every rank when the type has no positional fields.

pub trait DeserializeStruct

fn next_field<S: FieldSchema>(&mut self) -> Result<Option<i32>, DeserializeError>

fn value<T: Deserialize>(&mut self) -> Result<T, DeserializeError>

fn skip(&mut self) -> Result<(), DeserializeError>

fn end(&mut self) -> Result<(), DeserializeError>

pub trait DeserializeVariant

fn variant_name(&mut self) -> Result<String, DeserializeError>

fn disc(&mut self) -> Result<i32, DeserializeError>

fn payload<T: Deserialize>(&mut self) -> Result<T, DeserializeError>

fn is_unit(&mut self) -> Result<bool, DeserializeError>

fn end(&mut self) -> Result<(), DeserializeError>

pub trait Visitor

fn visit_null(&mut self) -> Result<Self::Value, DeserializeError>

fn visit_bool(&mut self, v: bool) -> Result<Self::Value, DeserializeError>

fn visit_f64(&mut self, v: f64) -> Result<Self::Value, DeserializeError>

fn visit_i64(&mut self, v: i64) -> Result<Self::Value, DeserializeError>

Integer visits. Self-describing binary formats (CBOR) call these to preserve full integer precision; the defaults widen to f64 so a visitor that only cares about JSON-style numbers keeps working.

fn visit_u64(&mut self, v: u64) -> Result<Self::Value, DeserializeError>

fn visit_i128(&mut self, v: i128) -> Result<Self::Value, DeserializeError>

fn visit_u128(&mut self, v: u128) -> Result<Self::Value, DeserializeError>

fn visit_string(&mut self, v: String) -> Result<Self::Value, DeserializeError>

fn visit_bytes(&mut self, _v: ByteList) -> Result<Self::Value, DeserializeError>

Byte-string visit (CBOR major type 2; JSON base64). Defaults to an UnexpectedType error so text-only visitors are unaffected.

fn visit_seq<A: DeserializeSeq>(&mut self, seq: &mut A) -> Result<Self::Value, DeserializeError>

fn visit_map<A: DeserializeMap>(&mut self, map: &mut A) -> Result<Self::Value, DeserializeError>

fn visit_unknown(&mut self, _raw: ByteList) -> Result<Self::Value, DeserializeError>

Opaque passthrough for a format item the value model cannot represent (e.g. an unassigned CBOR simple value or an uninterpreted tag). Only self-describing binary formats call this; defaults to an error.

fn visit_undefined(&mut self) -> Result<Self::Value, DeserializeError>

The CBOR undefined simple value (major 7, value 23). Distinct from null: a dynamic value model (core:value) keeps its own Undefined arm. The default collapses it to null so visitors that do not model the distinction (e.g. JSON) keep working.

pub trait Deserializer

fn deserialize_i32(&mut self) -> Result<i32, DeserializeError>

fn deserialize_i64(&mut self) -> Result<i64, DeserializeError>

fn deserialize_u32(&mut self) -> Result<u32, DeserializeError>

fn deserialize_u64(&mut self) -> Result<u64, DeserializeError>

fn deserialize_i128(&mut self) -> Result<i128, DeserializeError>

fn deserialize_u128(&mut self) -> Result<u128, DeserializeError>

fn deserialize_f32(&mut self) -> Result<f32, DeserializeError>

fn deserialize_f64(&mut self) -> Result<f64, DeserializeError>

fn deserialize_bool(&mut self) -> Result<bool, DeserializeError>

fn deserialize_char(&mut self) -> Result<char, DeserializeError>

fn deserialize_string(&mut self) -> Result<String, DeserializeError>

fn deserialize_bytes(&mut self) -> Result<ByteList, DeserializeError>

Deserialize a byte string. Self-describing binary formats read a native byte string; JSON reads base64. The default reads a sequence of u8.

fn is_null(&mut self) -> Result<bool, DeserializeError>

fn begin_seq(&mut self) -> Result<Self::SeqAccess, DeserializeError> with stores[self]

fn begin_map(&mut self) -> Result<Self::MapAccess, DeserializeError> with stores[self]

fn begin_struct(&mut self, name: &String, num_fields: i32) -> Result<Self::StructAccess, DeserializeError> with stores[self]

fn begin_variant(&mut self, type_name: &String, num_cases: i32) -> Result<Self::VariantAccess, DeserializeError> with stores[self]

fn deserialize_any<V: Visitor>(&mut self, visitor: &mut V) -> Result<V::Value, DeserializeError>

pub trait Deserialize

fn deserialize<D: Deserializer>(d: &mut D) -> Result<Self, DeserializeError>

fn deserialize_next_element_from_seq<S: DeserializeSeq>(seq: &mut S) -> Result<Self, DeserializeError>

Deserialize the next element from a sequence access. Used by variadic tuple deserialization via type pack expansion.

Structs

pub struct SerializeError

kind: SerializeErrorKind

message: String

pub struct DeserializeError

kind: DeserializeErrorKind

message: String

offset: i64

pub fn unexpected_type(msg: String, offset: i64) -> DeserializeError

pub fn missing_field(name: String) -> DeserializeError

pub fn invalid_value(msg: String, offset: i64) -> DeserializeError

pub fn malformed(msg: String, offset: i64) -> DeserializeError

pub fn eof(offset: i64) -> DeserializeError

pub fn trailing(offset: i64) -> DeserializeError

pub fn overflow(msg: String, offset: i64) -> DeserializeError

Enums

pub enum SerializeErrorKind

UnsupportedValue

Custom

pub enum DeserializeErrorKind

UnexpectedType

MissingField

UnknownVariant

DuplicateField

InvalidValue

Overflow

MalformedInput

TrailingData

Eof

Custom