Skip to main content

harmos_domain/schema/
declaration.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10// Static Shared Type Declarations And Inert Metadata
11
12/* === Modules === */
13
14/* === Re-Exports === */
15
16/* === Imports === */
17
18// Standard Library Imports
19use std::any::TypeId;
20use std::collections::HashMap;
21use std::fmt;
22use std::mem::size_of;
23// Third Party Imports
24use serde::{Deserialize, Serialize};
25// Local Imports
26use super::graph::{self, Error, Schema};
27use super::{Cardinality, MAX_NAME_BYTES};
28use crate::config::SchemaSettings;
29use crate::inventory::{digits, number, quoted, quoted_len, write};
30
31/* === Constants === */
32
33const HEADER: &[u8] = b"{\"kind\":\"schema\",\"name\":";
34const FIELDS: &[u8] = b",\"fields\":[";
35const NAME: &[u8] = b"{\"name\":";
36const TAG: &[u8] = b",\"tag\":";
37const KIND: &[u8] = b",\"kind\":{\"type\":";
38const REFERENCE: &[u8] = b",\"definition\":";
39const CARDINALITY: &[u8] = b"},\"cardinality\":";
40
41/* === Macros === */
42
43/* === Type Aliases === */
44
45pub type Field<R = Definition> = graph::Field<R>;
46pub type Kind<R = Definition> = graph::Kind<R>;
47
48/* === Structs === */
49
50#[derive(Clone, Copy)]
51pub struct Definition {
52    pub name: &'static str,
53
54    pub default_variant: Option<usize>,
55
56    pub identity: fn() -> TypeId,
57    pub fields: fn() -> &'static [Field<Definition>],
58    pub marker: fn() -> &'static [u8],
59}
60
61#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
62#[serde(from = "Fragment", into = "Fragment")]
63pub struct Named {
64    pub name: String,
65    pub fields: Vec<Field<String>>,
66}
67
68// Bounded Static Storage For Names Of Generic Message Shapes.
69pub struct Name {
70    bytes: [u8; MAX_NAME_BYTES],
71    length: usize,
72}
73
74struct Plan {
75    declarations: Vec<Definition>,
76    indices: HashMap<&'static str, usize>,
77    remaining_bytes: usize,
78    remaining_work: usize,
79}
80
81/* === Enums === */
82
83#[derive(Serialize, Deserialize)]
84#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
85enum Fragment {
86    Schema { name: String, fields: Vec<Field<String>> },
87}
88
89/* === Traits === */
90
91/* === Implementations === */
92
93impl PartialEq for Definition {
94    fn eq(&self, other: &Self) -> bool {
95        self.name == other.name && (self.identity)() == (other.identity)()
96    }
97}
98impl Eq for Definition {}
99
100impl Name {
101    pub const fn new(owner: &str, arguments: &[&str]) -> Self {
102        let mut name = Self { bytes: [0; MAX_NAME_BYTES], length: 0 };
103        name.push(owner);
104        if !arguments.is_empty() {
105            name.push("<");
106            let mut index = 0;
107            while index < arguments.len() {
108                if index > 0 {
109                    name.push(",");
110                }
111                name.push(arguments[index]);
112                index += 1;
113            }
114            name.push(">");
115        }
116        name
117    }
118
119    pub const fn as_str(&self) -> &str {
120        match std::str::from_utf8(self.bytes.split_at(self.length).0) {
121            Ok(name) => name,
122            Err(_) => panic!("schema names originate from valid UTF-8"),
123        }
124    }
125
126    const fn push(&mut self, part: &str) {
127        assert!(part.len() <= MAX_NAME_BYTES - self.length, "schema name exceeds its bound");
128        let mut index = 0;
129        while index < part.len() {
130            self.bytes[self.length] = part.as_bytes()[index];
131            self.length += 1;
132            index += 1;
133        }
134    }
135}
136
137impl Definition {
138    pub const fn of<T: super::Described + ?Sized>() -> Self {
139        Self {
140            name: T::NAME,
141            default_variant: T::DEFAULT_VARIANT,
142            identity: TypeId::of::<T>,
143            fields: fields::<T>,
144            marker: marker::<T>,
145        }
146    }
147}
148
149impl Named {
150    pub fn decode<'a>(fragments: impl IntoIterator<Item = &'a [u8]>, settings: &SchemaSettings) -> Result<Vec<Self>, Error> {
151        let mut budget = Plan::new(settings);
152        let mut declarations = Vec::new();
153        for encoded in fragments {
154            if encoded.len() > crate::FRAGMENT_LIMIT {
155                return Err(Error::Budget);
156            }
157            // Flat JSON Input Bounds Parser Allocations Before Decoding Each Type.
158            budget.charge(encoded.len().checked_mul(8).ok_or(Error::Budget)? + 4 * size_of::<Self>(), encoded.len() + 1)?;
159            let declaration: Self = serde_json::from_slice(encoded).map_err(|_| Error::Field {
160                field: "schema fragment".into(),
161                reason: "invalid schema metadata",
162            })?;
163            declarations.push(declaration);
164        }
165        Ok(declarations)
166    }
167}
168
169impl From<Fragment> for Named {
170    fn from(fragment: Fragment) -> Self {
171        let Fragment::Schema { name, fields } = fragment;
172        Self { name, fields }
173    }
174}
175impl From<Named> for Fragment {
176    fn from(named: Named) -> Self {
177        Self::Schema { name: named.name, fields: named.fields }
178    }
179}
180
181impl fmt::Debug for Definition {
182    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
183        formatter.debug_struct("Definition").field("name", &self.name).finish_non_exhaustive()
184    }
185}
186
187impl Schema {
188    // Resolve Inert Named Metadata Without Executing Artifact Code.
189    pub fn from_named(root: &str, declarations: &[Named], settings: &SchemaSettings) -> Result<Self, Error> {
190        resolve_named(&[("", root)], declarations, settings, false)
191    }
192
193    // Resolve Multiple Contract Directions From One Inert Type Dictionary.
194    pub fn from_named_roots(roots: &[(&str, &str)], declarations: &[Named], settings: &SchemaSettings) -> Result<Self, Error> {
195        resolve_named(roots, declarations, settings, true)
196    }
197
198    pub fn from_declaration(root: Definition, settings: &SchemaSettings) -> Result<Self, Error> {
199        let mut plan = Plan::new(settings);
200        plan.insert(root)?;
201        let schema = Self { root: 0, definitions: plan.compile()? };
202        schema.prepare(settings)?;
203        Ok(schema)
204    }
205
206    // Share Each Message Definition Across A Set Of Contract Directions.
207    pub fn from_declarations(roots: &[(&str, Definition)], settings: &SchemaSettings) -> Result<Self, Error> {
208        let mut plan = Plan::new(settings);
209        plan.charge(4 * size_of::<Vec<Field>>() + size_of::<Self>(), 1)?;
210        let mut fields = Vec::new();
211        for (index, (name, declaration)) in roots.iter().enumerate() {
212            plan.charge(4 * size_of::<Field<usize>>() + name.len(), name.len() + 1)?;
213            let tag = u32::try_from(index + 1).map_err(|_| Error::Budget)?;
214            fields.push(Field {
215                name: (*name).to_owned().into(),
216                tag,
217                kind: Kind::Message { definition: plan.insert(*declaration)? },
218                cardinality: Cardinality::Required,
219            });
220        }
221        let mut definitions = plan.compile()?;
222        let root = definitions.len();
223        definitions.push(fields);
224        let schema = Self { root, definitions };
225        schema.prepare(settings)?;
226        Ok(schema)
227    }
228}
229
230impl Plan {
231    fn compile(mut self) -> Result<Vec<Vec<Field<usize>>>, Error> {
232        let mut definitions = Vec::new();
233        let mut index = 0;
234        while index < self.declarations.len() {
235            let declaration = self.declarations[index];
236            let mut fields = Vec::new();
237            for field in (declaration.fields)() {
238                self.charge(4 * size_of::<Field<usize>>() + field.name.len(), field.name.len() + 1)?;
239                let kind = field.kind.try_map(|definition| self.insert(definition))?;
240                fields.push(Field {
241                    name: field.name.to_string().into(),
242                    tag: field.tag,
243                    kind,
244                    cardinality: field.cardinality,
245                });
246            }
247            definitions.push(fields);
248            index += 1;
249        }
250        Ok(definitions)
251    }
252    fn new(settings: &SchemaSettings) -> Self {
253        Self {
254            declarations: Vec::new(),
255            indices: HashMap::new(),
256            remaining_bytes: settings.preparation_bytes.get(),
257            remaining_work: settings.preparation_work.get(),
258        }
259    }
260    fn charge(&mut self, bytes: usize, work: usize) -> Result<(), Error> {
261        self.remaining_bytes = self.remaining_bytes.checked_sub(bytes).ok_or(Error::Budget)?;
262        self.remaining_work = self.remaining_work.checked_sub(work).ok_or(Error::Budget)?;
263        Ok(())
264    }
265    fn insert(&mut self, definition: Definition) -> Result<usize, Error> {
266        self.charge(0, definition.name.len() + 1)?;
267        if definition.name.is_empty() || definition.name.len() > MAX_NAME_BYTES || definition.name.chars().any(char::is_control) {
268            return Err(Error::Field {
269                field: super::diagnostic_name(definition.name),
270                reason: "invalid schema definition name",
271            });
272        }
273        if let Some(index) = self.indices.get(definition.name).copied() {
274            let original = self.declarations[index];
275            if (original.identity)() != (definition.identity)() {
276                return Err(Error::Field {
277                    field: definition.name.into(),
278                    reason: "schema definition name has multiple owners",
279                });
280            }
281            return Ok(index);
282        }
283        self.charge(4 * (size_of::<Definition>() + size_of::<Vec<Field>>() + size_of::<(&str, usize)>() + 1), 1)?;
284        let index = self.declarations.len();
285        self.declarations.push(definition);
286        self.indices.insert(definition.name, index);
287        Ok(index)
288    }
289}
290
291/* === Public Functions === */
292
293pub fn markers(root: Definition, settings: &SchemaSettings) -> Result<Vec<&'static [u8]>, Error> {
294    markers_many([root], settings)
295}
296
297pub fn markers_many(roots: impl IntoIterator<Item = Definition>, settings: &SchemaSettings) -> Result<Vec<&'static [u8]>, Error> {
298    let mut plan = Plan::new(settings);
299    for root in roots {
300        plan.insert(root)?;
301    }
302    let mut index = 0;
303    while index < plan.declarations.len() {
304        let declaration = plan.declarations[index];
305        for field in (declaration.fields)() {
306            plan.charge(0, 1)?;
307            if let Kind::Message { definition } = field.kind {
308                plan.insert(definition)?;
309            }
310        }
311        index += 1;
312    }
313    let output_bytes = plan.declarations.len().checked_mul(std::mem::size_of::<&[u8]>()).ok_or(Error::Budget)?;
314    plan.charge(output_bytes, 0)?;
315    Ok(plan.declarations.iter().map(|definition| (definition.marker)()).collect())
316}
317
318pub const fn encoded_len(name: &str, fields: &[Field<Definition>]) -> usize {
319    let mut length = crate::PREFIX.len() + HEADER.len() + quoted_len(name) + FIELDS.len() + 3;
320    let mut index = 0;
321    while index < fields.len() {
322        let field = &fields[index];
323        length += NAME.len()
324            + quoted_len(field_name(field))
325            + TAG.len()
326            + digits(field.tag as u64)
327            + KIND.len()
328            + quoted_len(kind_name(&field.kind))
329            + CARDINALITY.len()
330            + quoted_len(cardinality_name(field.cardinality))
331            + 1;
332        if let Kind::Message { definition } = &field.kind {
333            length += REFERENCE.len() + quoted_len(definition.name);
334        }
335        if index > 0 {
336            length += 1;
337        }
338        index += 1;
339    }
340    assert!(length - crate::PREFIX.len() - 1 <= crate::FRAGMENT_LIMIT);
341    length
342}
343
344pub const fn encode<const N: usize>(name: &str, fields: &[Field<Definition>]) -> [u8; N] {
345    assert!(N == encoded_len(name, fields));
346    encode_buffer(name, fields)
347}
348
349// Encode A Small Generic Shape Into Explicitly Bounded Static Storage.
350// The Caller Retains Only The `encoded_len` Prefix Of The Result.
351pub const fn encode_buffer<const N: usize>(name: &str, fields: &[Field<Definition>]) -> [u8; N] {
352    assert!(N >= encoded_len(name, fields), "schema marker exceeds its static storage");
353    let mut output = [0; N];
354    let mut cursor = 0;
355    write(&mut output, &mut cursor, crate::PREFIX);
356    write(&mut output, &mut cursor, HEADER);
357    quoted(&mut output, &mut cursor, name);
358    write(&mut output, &mut cursor, FIELDS);
359    let mut index = 0;
360    while index < fields.len() {
361        let field = &fields[index];
362        if index > 0 {
363            write(&mut output, &mut cursor, b",");
364        }
365        write(&mut output, &mut cursor, NAME);
366        quoted(&mut output, &mut cursor, field_name(field));
367        write(&mut output, &mut cursor, TAG);
368        number(&mut output, &mut cursor, field.tag as u64);
369        write(&mut output, &mut cursor, KIND);
370        quoted(&mut output, &mut cursor, kind_name(&field.kind));
371        if let Kind::Message { definition } = &field.kind {
372            write(&mut output, &mut cursor, REFERENCE);
373            quoted(&mut output, &mut cursor, definition.name);
374        }
375        write(&mut output, &mut cursor, CARDINALITY);
376        quoted(&mut output, &mut cursor, cardinality_name(field.cardinality));
377        write(&mut output, &mut cursor, b"}");
378        index += 1;
379    }
380    write(&mut output, &mut cursor, b"]}\0");
381    assert!(cursor == encoded_len(name, fields));
382    output
383}
384
385/* === Private Functions === */
386
387fn fields<T: super::Described + ?Sized>() -> &'static [Field<Definition>] {
388    T::FIELDS
389}
390
391fn marker<T: super::Described + ?Sized>() -> &'static [u8] {
392    T::MARKER
393}
394
395fn resolve_named(roots: &[(&str, &str)], declarations: &[Named], settings: &SchemaSettings, composite: bool) -> Result<Schema, Error> {
396    let mut budget = Plan::new(settings);
397    let mut dictionary = HashMap::new();
398    for declaration in declarations {
399        let name = declaration.name.as_str();
400        budget.charge(4 * size_of::<(&str, &Named)>() + name.len(), name.len() + 1)?;
401        if name.is_empty() || name.len() > MAX_NAME_BYTES || name.chars().any(char::is_control) {
402            return Err(Error::Field {
403                field: super::diagnostic_name(name),
404                reason: "invalid schema definition name",
405            });
406        }
407        // Charge The Already Decoded Input Alongside Output And Lookup Scratch.
408        budget.charge(declaration.fields.capacity() * size_of::<Field<String>>(), 1)?;
409        for field in &declaration.fields {
410            budget.charge(field.name.len(), field.name.len() + 1)?;
411            if let Kind::Message { definition } = &field.kind {
412                budget.charge(definition.len(), definition.len() + 1)?;
413            }
414        }
415        if let Some(original) = dictionary.insert(name, declaration) {
416            budget.charge(0, declaration.fields.len() + 1)?;
417            if original != declaration {
418                return Err(Error::Field {
419                    field: name.into(),
420                    reason: "schema definition name has conflicting metadata",
421                });
422            }
423        }
424    }
425    let missing = |name: &str| Error::Field {
426        field: super::diagnostic_name(name),
427        reason: "schema definition is absent",
428    };
429    let mut names = Vec::new();
430    let mut indices = HashMap::new();
431    let mut directions = Vec::new();
432    budget.charge(4 * size_of::<Vec<Field>>() + size_of::<Schema>(), 1)?;
433    for (index, (direction, root)) in roots.iter().enumerate() {
434        let declaration = dictionary.get(root).ok_or_else(|| missing(root))?;
435        let name = declaration.name.as_str();
436        let definition = if let Some(index) = indices.get(name) {
437            *index
438        } else {
439            budget.charge(4 * (size_of::<&str>() + size_of::<(&str, usize)>()), name.len() + 1)?;
440            let index = names.len();
441            names.push(name);
442            indices.insert(name, index);
443            index
444        };
445        if composite {
446            budget.charge(4 * size_of::<Field<usize>>() + direction.len(), direction.len() + 1)?;
447            directions.push(Field {
448                name: (*direction).to_owned().into(),
449                tag: u32::try_from(index + 1).map_err(|_| Error::Budget)?,
450                kind: Kind::Message { definition },
451                cardinality: Cardinality::Required,
452            });
453        }
454    }
455    let mut definitions = Vec::new();
456    let mut index = 0;
457    while index < names.len() {
458        let declaration = dictionary[names[index]];
459        let mut fields = Vec::new();
460        budget.charge(4 * (size_of::<&str>() + size_of::<(&str, usize)>() + size_of::<Vec<Field>>()), 1)?;
461        for field in &declaration.fields {
462            budget.charge(4 * size_of::<Field<usize>>() + field.name.len(), field.name.len() + 1)?;
463            let kind = field.kind.clone().try_map(|name| {
464                let declaration = dictionary.get(name.as_str()).ok_or_else(|| missing(&name))?;
465                let name = declaration.name.as_str();
466                if let Some(index) = indices.get(name) {
467                    return Ok(*index);
468                }
469                budget.charge(4 * (size_of::<&str>() + size_of::<(&str, usize)>()), name.len() + 1)?;
470                let index = names.len();
471                indices.insert(name, index);
472                names.push(name);
473                Ok(index)
474            })?;
475            fields.push(Field {
476                name: field.name.clone(),
477                tag: field.tag,
478                kind,
479                cardinality: field.cardinality,
480            });
481        }
482        definitions.push(fields);
483        index += 1;
484    }
485    let root = if composite {
486        let root = definitions.len();
487        definitions.push(directions);
488        root
489    } else {
490        0
491    };
492    let schema = Schema { root, definitions };
493    schema.prepare(settings)?;
494    Ok(schema)
495}
496
497const fn field_name(field: &Field<Definition>) -> &str {
498    match &field.name {
499        std::borrow::Cow::Borrowed(name) => name,
500        std::borrow::Cow::Owned(_) => panic!("constant schema names must be borrowed"),
501    }
502}
503const fn kind_name(kind: &Kind<Definition>) -> &'static str {
504    match kind {
505        Kind::Bool => "bool",
506        Kind::U32 => "u32",
507        Kind::U64 => "u64",
508        Kind::I32 => "i32",
509        Kind::I64 => "i64",
510        Kind::F32 => "f32",
511        Kind::F64 => "f64",
512        Kind::String => "string",
513        Kind::Bytes => "bytes",
514        Kind::Message { .. } => "message",
515    }
516}
517const fn cardinality_name(cardinality: Cardinality) -> &'static str {
518    match cardinality {
519        Cardinality::Required => "required",
520        Cardinality::Optional => "optional",
521        Cardinality::Repeated => "repeated",
522        Cardinality::Variant => "variant",
523    }
524}
525
526/* === Tests === */