No matching definitions.

tur/serial

stdlib/serial.tur

serializable continuations for persistent workflow state.

Defines the Serializable typeclass with primitive and container instances.

Since: Phase 21

defopaque linear

Bytes

(defopaque Bytes :ptr<void> :linear)
defn

bytes-alloc

(bytes-alloc [n :int] :Bytes)

allocate a zeroed length-prefixed byte buffer of n bytes.

nnumber of data bytes to allocate (not counting the 8-byte length prefix)

A :ptr<void> to the new bytes value; free with bytes-free.

(def b (bytes-alloc 16))  ; => 16-byte zeroed buffer

Since: Phase 21

defn

bytes-len

(bytes-len [^borrow b :Bytes] :int)

return the number of data bytes stored in a bytes value.

bbytes pointer from bytes-alloc or a serialize call

The data length as :int (0 for null pointer).

Since: Phase 21

defn

bytes-data

(bytes-data [^borrow b :Bytes] :ptr<void>)

return a raw pointer to the data region of a bytes value (past the length prefix).

bbytes pointer from bytes-alloc or a serialize call

:ptr<void> to the first data byte, or NULL for a null pointer.

Since: Phase 21

defn

bytes-free

(bytes-free [b :Bytes] :void)

free a bytes value allocated by bytes-alloc or serialize.

bbytes pointer to free

Since: Phase 21

defn

bytes-concat

(bytes-concat [^borrow a :Bytes ^borrow b :Bytes] :Bytes)

concatenate two bytes values into a new heap-allocated bytes value.

afirst bytes value (may be null, treated as empty)
bsecond bytes value (may be null, treated as empty)

A new bytes value containing all bytes of a followed by all bytes of b.

(bytes-concat ba bb)  ; => new bytes with ba then bb

Since: Phase 21

defclass

Serializable

(defclass Serializable [a])

typeclass for types that can be marshalled to/from bytes.

(serialize [x] :ptr<void>)

marshal x to a length-prefixed bytes value

(deserialize [b :ptr<void>] :a)

unmarshal from bytes; panics on malformed input

int, bool, float, cstr, ptr<void>, Pair, Option

Since: Phase 21

definstance

Serializable[int]

(definstance Serializable [int])

serialize/deserialize int64 as 8 little-endian bytes.

Since: Phase 21

definstance

Serializable[bool]

(definstance Serializable [bool])

serialize/deserialize bool as a single byte (0 = false, 1 = true).

Since: Phase 21

definstance

Serializable[float]

(definstance Serializable [float])

serialize/deserialize float64 as 8 bytes IEEE 754 little-endian.

Since: Phase 21

definstance

Serializable[cstr]

(definstance Serializable [cstr])

serialize/deserialize a cstr as a 4-byte LE length prefix followed by UTF-8 bytes.

Since: Phase 21

definstance

Serializable[ptr<void>]

(definstance Serializable [ptr<void>])

serialize/deserialize a bytes value as an 8-byte LE length followed by raw data.

Since: Phase 21

defn

serial-pair-bytes

(serial-pair-bytes [fst :int snd :int] :ptr<void>)

raw [len=16][fst][snd] Pair byte layout from two int64 element carriers.

Fixed-arity (takes the element carriers as plain ints, not the Pair), so the (serialize ...) instance body that calls it stays pure-Turmeric rather than inline-C. That lets the per-instantiation spec machinery (M4c Path A) mint a typed serialize_Pair__spec__(Pair__int__int) and dispatch a by-value Pair directly -- no concrete->carrier bridge spill. The byte layout is identical to the prior inline-C body, so deserialize is unchanged.

fstfirst element's int64 carrier
sndsecond element's int64 carrier

A raw :ptr<void> bytes value (see the module note on the raw-buffer surface).

Since: end-to-end-monomorphization (M4 bucket-D)

definstance

Serializable[Pair]

(definstance Serializable [Pair])

serialize a Pair[A B] as its two int64 element carriers.

Layout: [int64 len=16][int64 fst][int64 snd].

Since: cps-transform-plan (value-typed cont env codec)

definstance

Serializable[Option]

(definstance Serializable [Option])

serialize an Option[A] as a presence flag + carrier.

Layout: [int64 len=16][int64 is-some][int64 value].

Since: cps-transform-plan (value-typed cont env codec)

defn

cont-to-file

(cont-to-file [b :ptr<void> path :cstr] :int)

write a serialised continuation bytes value to a file.

bbytes value from serial-cont->bytes / save-cont!
pathfilesystem path to write (overwritten if it exists)

1 on success, 0 on failure.

(cont-to-file k-bytes "/tmp/checkpoint.bin")  ; => 1

Since: Phase 21

defn

cont-from-file

(cont-from-file [path :cstr] :ptr<void>)

read a serialised continuation bytes value from a file.

pathfilesystem path previously written by cont-to-file

A bytes :ptr<void> on success, NULL on any I/O or allocation failure.

(def k-bytes (cont-from-file "/tmp/checkpoint.bin"))

Since: Phase 21

defn

serial-cont->bytes

(serial-cont->bytes [k :serial-cont] :ptr<void>)

marshal a captured continuation to a bytes value.

The typed spelling of save-cont!: walks the frame chain k and writes each frame's stable tag/name plus its environment (int inline, cstr and Serializable envs by value) to a length-prefixed buffer. No code address is written, so the bytes are valid in another process running the SAME program.

Compiled programs only: the frame chain this walks is the compiled program's. tur --interpret keeps its own continuation structure and stops with inline-C defn 'serial-cont->bytes' takes a parameter of type cont<int>. bytes->serial-cont and the *-cont! / cont-*-file helpers are the same.

kthe continuation the serial-shift receiver was passed

A caller-owned bytes :ptr<void> ({int64 len; data}), or NULL if k is nil.

(defn stash [k : serial-cont] : int
  (do (cont-to-file (serial-cont->bytes k) "/tmp/k.bin") 0))
(serial-reset (+ 10 (serial-shift stash 0)))

Since: Phase 21 (typed surface 2026-09-02)

defn

bytes->serial-cont

(bytes->serial-cont [b :ptr<void>] :(Result serial-cont cstr))

rebuild a continuation from bytes, or say why not.

Validates the buffer before touching the runtime: every frame record must fit, carry a known tag, and -- for a call frame -- name a frame this program registered, with the env kind that frame was registered with. A buffer written by a different program (or a different build whose frame names moved) is therefore an Err naming the problem rather than an abort or a resumed garbage chain. resume-cont! and image/blob-resume! run the same check and panic instead.

Validation is integrity, not authenticity: a well-formed buffer from an untrusted source still rebuilds a continuation of this program's own frames with the envs it chose. Authenticate bytes that crossed a trust boundary before handing them here (the guestbook example keeps them server-side under an HMAC-signed name).

ba bytes value from serial-cont->bytes / save-cont! / cont-from-file

(Ok k) with a resumable serial-cont, or (Err msg) with a static cstr: "null bytes", "short buffer", "bad frame count", "truncated frame", "frame name too long", "unknown frame (written by a different program?)", "truncated env", "bad env kind", "bad frame tag", "env kind does not match the frame" -- each prefixed with "bytes->serial-cont: ".

(match (bytes->serial-cont (cont-from-file "/tmp/k.bin"))
  (Ok k)  (serial-resume k 5)
  (Err m) (do (println m) 0))

Since: Phase 21 (typed surface 2026-09-02)

defn

serial-resume-owned

(serial-resume-owned [k :serial-cont v :int] :int)

resume a rebuilt continuation, then release it.

A continuation from bytes->serial-cont belongs to the program, and a resume runs a copy of it, so nothing else ever frees it. A serial-cont is consumed by its resume, which leaves no later point to free it at -- so this resumes and frees in one step. Only for a continuation that bytes->serial-cont returned: the one a serial-shift receiver is handed is the compiler's to free (serial-resume it), and freeing it here would free it twice. The strings a cstr-env frame was rebuilt with stay allocated, since the resumed computation may have returned one of them.

ka serial-cont from bytes->serial-cont
vthe value to fill the hole with

The resumed computation's result, as serial-resume.

(match (bytes->serial-cont b)
  (Ok k)  (serial-resume-owned k 5)
  (Err m) (do (println m) 0))

Since: 2026-10-07 (serial-cont-escaped-or-deserialized-chain-leaks)

defn

serial-cont-free

(serial-cont-free [k :serial-cont] :nil)

release a rebuilt continuation without resuming it.

For a continuation from bytes->serial-cont that the program decides not to resume. Same restriction as serial-resume-owned: never the receiver's k.

ka serial-cont from bytes->serial-cont
(match (bytes->serial-cont b) (Ok k) (serial-cont-free k) (Err m) nil)

Since: 2026-10-07 (serial-cont-escaped-or-deserialized-chain-leaks)

defn

serial-bytes-free

(serial-bytes-free [b :ptr<void>] :nil)

release a buffer from serial-cont->bytes.

serial-cont->bytes, save-cont! and cont-from-file return a caller-owned malloc'd buffer as a bare ptr<void> (cont-to-file and bytes->serial-cont take that form), so bytes-free, which takes the linear Bytes, does not apply. Free it with this once it has been written or rebuilt. NULL is a no-op.

ba buffer from serial-cont->bytes / save-cont! / cont-from-file
(let [b (serial-cont->bytes k)]
  (cont-to-file b "/tmp/k.bin")
  (serial-bytes-free b))

Since: 2026-10-07 (serial-cont-escaped-or-deserialized-chain-leaks)

defn

serial-resume

(serial-resume [k :serial-cont v :int] :int)

resume a continuation with a value.

(serial-resume k v) is (k v): the enclosing serial-reset's rest of the computation runs with v in the hole and its result comes back. Works on the continuation the serial-shift receiver was handed and on one rebuilt by bytes->serial-cont alike.

ka serial-cont
vthe value to fill the hole with

The resumed computation's result.

(defn sk [k : serial-cont] : int (serial-resume k 5))
(serial-reset (+ 10 (serial-shift sk 0)))   ; => 15

Since: Phase 21 (typed surface 2026-09-02)