Files
mesh-sdk/go/stateobjects/ref.go
T
jschoubben 5fa64be894 Revert the revert of G's mesh-sdk merge (#191): G's sdk stands again over reader release 3
Main reverted G's half merge (#189, reverted by 8afc3eb in #191) and then took the reader release's S1-S5, which
copied G's code. G's form holds where they differ (process_bus.go, seats.go, state.go and their tests); the
release's kept names stay so main's callers keep building: SeatViewPrefix beside SeatReadPrefix, and QueueInvoke's
empty strings on not-ok (with its test TestQueueInvoke). The tree differs from G's head f30dee54 only by those and
the release's two tests (objects cap option, seat states and stream kinds).

Builds: design 47 G (the milestone's sdk part, as at f30dee54)

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-13 12:49:56 +01:00

72 lines
2.6 KiB
Go

// Package stateobjects keeps values of any size on the bus (novox/hq ADR 0666 §16, ADR 0595 §9): a value over the bus's
// limit for one value, or a verb reply or an event over the limit for one message, is put in an object store and only its
// reference travels. It is a small package of its own, imported only by the modules that use it: the module library (the
// root package) and the process package do not import it, so their importers are not rebuilt when it changes. It names no
// seat and no module, and imports no contracts module.
package stateobjects
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
)
// FormVersion is the version of the reference form; a reader refuses a reference of another.
const FormVersion = 1
// refField is the one field of a body that is a reference.
const refField = "mesh-object"
// Ref names an object in an object store: a body that is exactly `{"mesh-object": Ref}` is a reference, and anything
// else is a value.
type Ref struct {
// Store is the object store's name as its reader asks for it: a bundle's local name, or the name a process opens.
Store string `json:"store"`
// Object is the object's name in that store.
Object string `json:"object"`
// Size is the object's size in bytes.
Size int64 `json:"size"`
// Digest is the hex SHA-256 of the object's bytes; a reader checks it after the read.
Digest string `json:"sha256"`
// Form is FormVersion.
Form int `json:"form"`
}
func (r Ref) valid() bool {
if r.Store == "" || r.Object == "" || r.Size < 0 || r.Form != FormVersion || len(r.Digest) != 64 {
return false
}
_, err := hex.DecodeString(r.Digest)
return err == nil
}
// Wrap is the body that holds r.
func Wrap(r Ref) []byte {
raw, _ := json.Marshal(map[string]Ref{refField: r})
return raw
}
// ReadRef reads a body as a reference: ok is false for a value, including one that only looks like a reference (another
// field beside it, a field it does not know, a digest that is no digest, another form).
func ReadRef(body []byte) (Ref, bool) {
var outer map[string]json.RawMessage
if err := json.Unmarshal(body, &outer); err != nil || len(outer) != 1 {
return Ref{}, false
}
raw, ok := outer[refField]
if !ok {
return Ref{}, false
}
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
var r Ref
if err := dec.Decode(&r); err != nil || !r.valid() {
return Ref{}, false
}
return r, true
}
// errLooksLikeRef refuses a value that would be read back as a reference.
var errLooksLikeRef = fmt.Errorf("the value is exactly a reference to an object (a body of the one field %q): it would be read as one", refField)