Skip to content

Latest commit

 

History

History
156 lines (114 loc) · 3.8 KB

api.md

File metadata and controls

156 lines (114 loc) · 3.8 KB

API

Serdde has a typed protocol layer, three wire backends, and an optional dynamic Value backend.

Derives

from serdde.macros import Deserialize
from serdde.macros import Serde
from serdde.macros import Serialize

@derive(Serialize) generates methods equivalent to:

def serdde_field_count(self: &const[Self]) -> usize:
    ...

def serdde_serialize[Writer](
    self: &const[Self],
    output: &Writer,
) -> Result[bool, SerddeError]:
    ...

@derive(Deserialize) generates a static method:

def serdde_deserialize[Reader](
    input: &const[Reader],
) -> Result[Self, SerddeError]:
    ...

@derive(Serde) generates both directions. Writers and readers are generic, so one expansion serves JSON, CBOR, DSON, Value, protocol probes, and third-party backends.

Typed Wire APIs

JSON:

from serdde.json import dumps
from serdde.json import dumps_into
from serdde.json import loads

text = dumps(player)
ready = loads[Player](text.value)

buffer = ""
dumps_into(player, buffer)

CBOR and DSON have the same typed API under serdde.cbor and serdde.dson. CBOR returns binary bytes stored in str; it is not UTF-8 text.

dumps_into clears and reuses the destination string's allocation. It does not append to the previous contents.

Adapters

An adapter is format-neutral:

class PairSerde:
    def serialize[Writer](
        value: &const[std.pair[std.string, i32]],
        output: &Writer,
    ) -> Result[bool, SerddeError]:
        ...

    def deserialize[Reader](
        input: &const[Reader],
    ) -> Result[std.pair[std.string, i32], SerddeError]:
        ...

Apply it to a field:

@derive(Serde)
class Entry:
    @Serde(adapter="PairSerde")
    pair: std.pair[std.string, i32]

Apply it to a standalone value:

from serdde.json import dumps_with
from serdde.json import loads_with

text = dumps_with[std.pair[std.string, i32], PairSerde](pair)
pair = loads_with[std.pair[std.string, i32], PairSerde](text.value)

dumps_into_with is the reusable-buffer form. These three adapter calls also exist in serdde.cbor and serdde.dson.

Dynamic Value

Dynamic trees are explicit:

from serdde.json_value import dumps_value
from serdde.json_value import loads_value
from serdde.value import Value

tree: Result[Value, SerddeError] = loads_value(source)
text = dumps_value(tree.value)

Use serdde.cbor_value and serdde.dson_value for the other wire formats.

Typed conversion without a wire format is provided by serdde.convert:

from serdde.convert import from_value
from serdde.convert import to_value

tree = to_value(player)
player = from_value[Player](tree.value)

to_value_with and from_value_with apply an adapter to this explicit dynamic backend.

Value represents null, bool, signed integer, unsigned integer, float, UTF-8 string, sequence, or ordered string-keyed object. Object insertion order is retained for dynamic text output.

Errors

Import SerddeError, ErrorKind, PathSegment, and PathKind from serdde.error.

match loads[Player](source):
    case Err(error):
        print(error.path_string() + ": " + error.message)

path_string() renders paths such as $.players[2].name. Errors also carry a format name and, where available, one-based line/column plus byte offset. Integer overflow, kind mismatch, missing fields, duplicate aliases, unknown fields under strict policy, invalid UTF-8, malformed input, and failed untagged variants use structured errors rather than native-library messages.

Handwritten Codecs

A Dudu type can implement the generated protocol methods directly. This is appropriate when the wire representation differs from the in-memory model. An adapter is preferable when the type is external or when more than one wire representation is useful.