soothfast v0.1.0

soothfast-spec API reference#

Generated by cargo soothfast docs reference Measurements and verified claims come from the latest baseline; CI gates them.

soothfast_spec#

DeclaredOp struct#

rust · ignore
pub struct DeclaredOp

One operation a spec declares.

RouteDecl struct#

rust · ignore
pub struct RouteDecl

One #[soothfast::route] annotation from the code.

SpecKind enum#

rust · ignore
pub enum SpecKind

Spec dialects soothfast reads and writes.

sniff_kind function#

rust · ignore
pub fn sniff_kind(filename: &str, text: &str) -> Option<SpecKind>

Sniff the dialect from filename + content.

soothfast_spec::SpecKind#

render function#

rust · ignore
pub fn render(self, path: &str, value: &Value) -> String

Serialize a document for writing to path.

GraphQL ignores the extension because SDL is its only serialization; the rest honour .json and default to the dialect's usual form.

soothfast_spec::asyncapi#

document function#

rust · ignore
pub fn document(info: &Info, ops: &[Operation]) -> Document

Assemble an AsyncAPI 3.0 document.

soothfast_spec::asyncapi::diff#

diff function#

rust · ignore
pub fn diff(old: &Value, new: &Value) -> Vec<Change>

Compare two generated documents, oldest first.

soothfast_spec::compat#

Change struct#

rust · ignore
pub struct Change

One difference between two versions of a spec.

Direction enum#

rust · ignore
pub enum Direction

Which way the data flows, which decides what "required" costs.

SchemaDiff struct#

rust · ignore
pub struct SchemaDiff<'a>

Compares schemas belonging to two revisions of a document.

Both documents are held because a $ref only means anything relative to the document it came from: the same pointer can name different shapes on either side of the comparison.

Severity enum#

rust · ignore
pub enum Severity

Whether a change can break an existing consumer.

compare_keys function#

rust · ignore
pub fn compare_keys<F>( changes: &mut Vec<Change>, old: &BTreeMap<String, Value>, new: &BTreeMap<String, Value>, noun: &str, mut both: F, ) where F: FnMut(&mut Vec<Change>, &str, &Value, &Value),

Compare two maps of named entries, reporting bare presence changes and handing matched pairs to both.

Added and removed entries mean the same thing in every dialect — a tool, a channel, an operation or a field that appears or disappears — so only the wording and the severity of a removal differ between callers.

deref function#

rust · ignore
pub fn deref<'a>(doc: &'a Value, schema: &'a Value) -> &'a Value

Follow a local $ref to the schema it names, once.

Resolution is by JSON Pointer rather than by a fixed components/schemas prefix: dialects disagree on where shared schemas live (#/$defs/X inside one tool's schema, #/components/schemas/X at the document root), and the pointer already says which.

is_compatible function#

rust · ignore
pub fn is_compatible(changes: &[Change]) -> bool

True when nothing in the diff would break an existing consumer.

render function#

rust · ignore
pub fn render(v: &Value) -> String

A JSON value as it should read inside a diff message.

required_set function#

rust · ignore
pub fn required_set(schema: &Value) -> BTreeSet<&str>

The required names of an object schema.

sort function#

rust · ignore
pub fn sort(changes: &mut [Change])

Order a diff for reporting: breaking first, then by location, so output is stable between runs.

soothfast_spec::dialect#

Document struct#

rust · ignore
pub struct Document

A rendered document plus anything that had to be reconciled to build it.

Info struct#

rust · ignore
pub struct Info

Document metadata that no amount of code reading can derive.

Operation struct#

rust · ignore
pub struct Operation

One operation to emit, pairing spec identity with the inferred shape.

soothfast_spec::graphql#

document function#

rust · ignore
pub fn document(info: &Info, ops: &[Operation]) -> Document

Assemble a GraphQL type graph.

from_sdl function#

rust · ignore
pub fn from_sdl(text: &str) -> Result<Value, String>

to_sdl function#

rust · ignore
pub fn to_sdl(doc: &Value) -> String

soothfast_spec::graphql::diff#

diff function#

rust · ignore
pub fn diff(old: &Value, new: &Value) -> Vec<Change>

Compare two generated type graphs, oldest first.

soothfast_spec::mcp#

diff function#

rust · ignore
pub fn diff(old: &Value, new: &Value) -> Vec<Change>

Compare two generated tool manifests, oldest first.

A tool's arguments flow inward and its result flows outward, so the two schemas are compared in opposite directions — the same asymmetry OpenAPI has between a request body and a response.

document function#

rust · ignore
pub fn document(_info: &Info, ops: &[Operation]) -> Document

Assemble an MCP tool manifest.

info is unused: a tool manifest has no document-level metadata to carry, and inventing a wrapper object for it would break every client that reads the standard { "tools": [...] } shape.

soothfast_spec::openapi#

document function#

rust · ignore
pub fn document(info: &Info, ops: &[Operation]) -> Document

Assemble an OpenAPI 3.1 document.

verified claims
complexityclaimed O(n); growth drift x1.62 over sizes [16, 64, 256] (limit x2.5)
measured as `soothfast_spec::bench_openapi_document`
median walltime (ns)2350868
p99 walltime (ns)2720048
allocations/iter30152
allocated bytes/iter4715065

soothfast_spec::openapi::diff#

diff function#

rust · ignore
pub fn diff(old: &Value, new: &Value) -> Vec<Change>

Compare two generated documents, oldest first.

Returns every difference found, breaking ones first, then by location so output is stable between runs.

verified claims
complexityclaimed O(n); growth drift x1.76 over sizes [16, 64, 256] (limit x2.5)
measured as `soothfast_spec::bench_openapi_diff`
median walltime (ns)6489927
p99 walltime (ns)7967471
allocations/iter77722
allocated bytes/iter10815487

soothfast_spec::probe#

soothfast_spec::probe::assert#

Assertion struct#

rust · ignore
pub struct Assertion

One parsed assertion, kept with its source line for reporting.

soothfast_spec::probe::baseline#

Baseline struct#

rust · ignore
pub struct Baseline

The lock file: probe name → locked state.

Class enum#

rust · ignore
pub enum Class

A field's population class across accepted runs.

Findings struct#

rust · ignore
pub struct Findings

One probe's gate findings against the lock.

ProbeLock struct#

rust · ignore
pub struct ProbeLock

One probe's locked state.

soothfast_spec::probe::coverage#

declared_paths function#

rust · ignore
pub fn declared_paths(schema: &Value, spec: &Value) -> BTreeSet<String>

Enumerate the field paths schema declares, resolving $refs through the spec's components/schemas. allOf branches all apply and are merged; oneOf/anyOf children are conditional on which branch the value takes, so nothing below a union counts as declared. Recursive schemas stop at the repeated $ref; an open schema ({}) declares nothing below its own path.

soothfast_spec::probe::population#

populate function#

rust · ignore
pub fn populate(value: &Value) -> BTreeMap<String, bool>

Flatten value into path → populated. Paths are dotted, arrays collapse to [], and a path already seen stays populated once any occurrence carried data.

soothfast_spec::probe::shape#

Violation struct#

rust · ignore
pub struct Violation

One structural disagreement between response and schema.

response_schema function#

rust · ignore
pub fn response_schema<'a>( spec: &'a Value, method: &str, path: &str, status: u16, ) -> Option<&'a Value>

Find the JSON response schema the spec declares for method on the concrete path (path template segments {like_this} match anything), for the given status code.

template_matches function#

rust · ignore
pub fn template_matches(template: &str, concrete: &[&str]) -> bool

Whether a path template matches concrete path segments, treating any {seg} as a wildcard. Segment counts must agree.

validate function#

rust · ignore
pub fn validate(value: &Value, schema: &Value, spec: &Value) -> Vec<Violation>

Validate value against schema, resolving $refs through the spec's components/schemas. Returns every violation found.

soothfast_spec::proto#

ProtoField struct#

rust · ignore
pub struct ProtoField

One field, from either a .proto message or a struct's #[prost(..)] attributes. ty is the bare type token ("string", "sint64", ...).

ProtoReconciliation struct#

rust · ignore
pub struct ProtoReconciliation

Outcome of matching struct fields to a .proto message by tag number.

parse_proto_message function#

rust · ignore
pub fn parse_proto_message(text: &str, message: &str) -> Result<Vec<ProtoField>, String>

Parse the scalar fields of one message NAME { ... } block from .proto text. Nested message/oneof/enum bodies are skipped by brace depth, not descended into — this is a flat wire-format check, not a full parser.

parse_struct_prost_fields function#

rust · ignore
pub fn parse_struct_prost_fields( source: &str, struct_name: &str, ) -> Result<Vec<ProtoField>, String>

Extract #[prost(..)] field declarations from one struct in Rust source text, by scanning forward from each #[prost(..)] occurrence within the struct's brace-matched body to the field name it decorates. Deliberately not a full Rust parser (no syn) — same tradeoff as [parse_proto_message].

reconcile_proto function#

rust · ignore
pub fn reconcile_proto( spec_fields: &[ProtoField], code_fields: &[ProtoField], ) -> ProtoReconciliation

Match struct fields to declared .proto fields by tag number, then check that type (wire-compatibly) and name agree.

soothfast_spec::providers#

parse function#

rust · ignore
pub fn parse(kind: SpecKind, text: &str) -> Result<Vec<DeclaredOp>, String>

Parse one spec document into the operations it declares, dispatching on dialect: OpenAPI, AsyncAPI, and MCP tool schemas are YAML-or-JSON; GraphQL is SDL text.

soothfast_spec::reconcile#

Reconciliation struct#

rust · ignore
pub struct Reconciliation

Outcome of matching #[route] declarations against a spec's operations: what's missing on each side, what disagrees, and what lined up.

reconcile function#

rust · ignore
pub fn reconcile(declared: &[DeclaredOp], routes: &[RouteDecl]) -> Reconciliation

Match routes to declared operations by operation id, then check that method and path agree where the route states them.

soothfast_spec::schema#

Docs struct#

rust · ignore
pub struct Docs<'a>

Extraction struct#

rust · ignore
pub struct Extraction

A schema plus everything it referenced and everything it could not see.

Extractors struct#

rust · ignore
pub struct Extractors

Gap enum#

rust · ignore
pub enum Gap

A place the extractor could not derive a shape, and why.

Every gap names the exact type or field so the report is actionable, and carries an open schema rather than a guessed one.

Overrides struct#

rust · ignore
pub struct Overrides

Resolver struct#

rust · ignore
pub struct Resolver<'a>

RouteShape struct#

rust · ignore
pub struct RouteShape

TypeMapping enum#

rust · ignore
pub enum TypeMapping

TypeTable struct#

rust · ignore
pub struct TypeTable

extract_named function#

rust · ignore
pub fn extract_named<'a>( docs: impl Into<Docs<'a>>, table: &'a TypeTable, name: &str, ) -> Result<Extraction, String>

Extract the schema for a named type from a rustdoc JSON document.

Takes one document, or a [Docs] carrying the workspace-local crates the type may actually be defined in. Used for the #[route(response = "...")] override; signature-driven extraction goes through [Resolver::resolve] directly.

soothfast_spec::schema::graphql_attrs#

ContainerAttrs struct#

rust · ignore
pub struct ContainerAttrs

Container-level #[graphql(...)] options that change wire names.

FieldAttrs struct#

rust · ignore
pub struct FieldAttrs

Field-level #[graphql(...)] options.

Rename enum#

rust · ignore
pub enum Rename

How a container renames every field or enum item beneath it.

These are the six rules async-graphql accepts — notably not kebab-case, which serde has and async-graphql does not.

container function#

rust · ignore
pub fn container(raw: &[Value]) -> ContainerAttrs

Parse container-level #[graphql(...)] attributes.

field function#

rust · ignore
pub fn field(raw: &[Value]) -> FieldAttrs

Parse field-level #[graphql(...)] attributes.

variant function#

rust · ignore
pub fn variant(raw: &[Value]) -> FieldAttrs

Parse variant-level #[graphql(...)] attributes. Enum items take name but have no skip, so the field parser's answer is reused as-is.

wire_name_field function#

rust · ignore
pub fn wire_name_field(rust_name: &str, f: &FieldAttrs, c: &ContainerAttrs) -> String

The wire name of a field: name if given, else the container's rule.

wire_name_variant function#

rust · ignore
pub fn wire_name_variant(rust_name: &str, v: &FieldAttrs, c: &ContainerAttrs) -> String

The wire name of an enum item: name if given, else the container's rule.

soothfast_spec::schema::route_sig#

Parameter struct#

rust · ignore
pub struct Parameter

One query, path or header parameter.

RequestBody struct#

rust · ignore
pub struct RequestBody

A request body and the content type it arrives as.

Response struct#

rust · ignore
pub struct Response

One response, keyed by status code in [RouteShape].

Role enum#

rust · ignore
pub enum Role

What a handler parameter contributes to the wire contract.

infer function#

rust · ignore
pub fn infer<'a>( docs: impl Into<Docs<'a>>, table: &'a TypeTable, extractors: &Extractors, handler_path: &str, route_path: &str, overrides: &Overrides, ) -> Result<RouteShape, String>

Infer the wire contract of one handler.

handler_path is the #[route] id (app::routes::create_item) and route_path the URL template, whose {placeholders} name tuple path parameters that the Rust signature leaves positional.

soothfast_spec::schema::serde_attrs#

ContainerAttrs struct#

rust · ignore
pub struct ContainerAttrs

Container-level serde options that change the emitted schema.

FieldAttrs struct#

rust · ignore
pub struct FieldAttrs

Field-level serde options that change the emitted schema.

Rename enum#

rust · ignore
pub enum Rename

How a container renames every field or variant beneath it.

container function#

rust · ignore
pub fn container(raw: &[serde_json::Value]) -> ContainerAttrs

Parse container-level #[serde(...)] attributes.

field function#

rust · ignore
pub fn field(raw: &[serde_json::Value]) -> FieldAttrs

Parse field-level #[serde(...)] attributes.

serde_args function#

rust · ignore
pub fn serde_args(raw: &[serde_json::Value]) -> Vec<String>

Pull the serde(...) argument text out of rustdoc's attribute entries.

wire_name_field function#

rust · ignore
pub fn wire_name_field(rust_name: &str, f: &FieldAttrs, c: &ContainerAttrs) -> String

The wire name of a field, applying rename then the container rule.

wire_name_variant function#

rust · ignore
pub fn wire_name_variant(rust_name: &str, v: &ContainerAttrs, c: &ContainerAttrs) -> String

The wire name of a variant, applying rename then the container rule.

soothfast_spec::schema::types#

Subst type_alias#

rust · ignore
pub type Subst = BTreeMap<String, (Value, String)>

Generic parameter bindings captured at a concrete use site: parameter name → (resolved schema, display name used for component naming).

soothfast_spec::schema::types::Resolver#

resolve function#

rust · ignore
pub fn resolve(&mut self, ty: &Value, subst: &Subst, at: &str) -> Value

Resolve one rustdoc type node into a JSON Schema.

at is a human-readable location (Item.when) used for gap reports.

soothfast_spec::serialize#

from_text function#

rust · ignore
pub fn from_text(text: &str) -> Result<Value, String>

Parse YAML-or-JSON text into a JSON value (JSON is valid YAML, but JSON is tried first for exactness).

to_json function#

rust · ignore
pub fn to_json(value: &Value) -> String

Render a document as pretty JSON, for .json spec files.

Hand-rolled rather than serde_json::to_string_pretty for one reason: the same key order the YAML path uses. A tool manifest whose description sorts above its name is valid and unreadable, and the two serializations of one document should not disagree about what comes first.

to_yaml function#

rust · ignore
pub fn to_yaml(value: &Value) -> String

Render a document as YAML, with well-known keys in conventional order.

verified claims
complexityclaimed O(n); growth drift x1.31 over sizes [16, 64, 256] (limit x2.5)
measured as `soothfast_spec::bench_serialize_yaml`
median walltime (ns)6566755
p99 walltime (ns)7933175
allocations/iter74277
allocated bytes/iter8533615
built with cargo soothfast docs build source