Skip to main content

aion_package/
awl.rs

1//! The AWL provenance a `.aion` archive can carry: the authored document and
2//! the schema files that document imports.
3//!
4//! # Archive layout
5//!
6//! Two entry families share the `awl/` prefix, and both are rooted at the
7//! DOCUMENT'S OWN DIRECTORY — the same root an AWL checker resolves
8//! `schema("…")` imports against:
9//!
10//! ```text
11//! awl/document/<filename>          exactly one entry; the authored `.awl` file
12//! awl/schema/<relative path>       zero or more; each imported schema file
13//! ```
14//!
15//! The document entry keeps the original filename verbatim, and every schema
16//! entry keeps the document-relative path the document itself names, nesting
17//! included. That is what lets a consumer stage the pair back onto a
18//! filesystem and re-check the document exactly as it was checked when it was
19//! deployed: the source's `schema("schemas/brief.schema.json")` line resolves
20//! against the staged tree unchanged.
21//!
22//! # This is provenance, never identity
23//!
24//! An archived document does NOT participate in package identity. Two
25//! packages whose beams, manifest, and contract agree have the SAME
26//! [`crate::ContentHash`] whether one carries AWL source and the other does
27//! not, and whether their carried source differs. See [`crate::hash`] for the
28//! identity law this is a declared instance of; it is pinned by
29//! `awl_source_inclusion_does_not_change_manifest_version` in
30//! `crate::builder`.
31
32use std::collections::BTreeMap;
33
34pub(crate) const AWL_DOCUMENT_PREFIX: &str = "awl/document/";
35pub(crate) const AWL_SCHEMA_PREFIX: &str = "awl/schema/";
36
37/// The authored AWL document an archive was built from, with the schema files
38/// it imports.
39///
40/// The document is text (an AWL document is UTF-8 by construction — the lexer
41/// works on `&str`), so a consumer can parse it without re-validating an
42/// encoding. Schema files stay bytes: they are staged back onto a filesystem
43/// verbatim, and re-encoding them would change what the checker reads.
44#[derive(Clone, Debug, PartialEq, Eq)]
45pub struct AwlSource {
46    document_name: String,
47    document: String,
48    schemas: BTreeMap<String, Vec<u8>>,
49}
50
51impl AwlSource {
52    /// Creates an AWL provenance record from the document's original filename,
53    /// its source text, and its imported schema files keyed by
54    /// document-relative path.
55    ///
56    /// Names are validated when the archive is written, not here: an
57    /// unrepresentable name yields [`crate::PackageError::MalformedAwlEntry`]
58    /// from the write path, exactly as an unrepresentable module name does.
59    #[must_use]
60    pub fn new<I, N, B>(
61        document_name: impl Into<String>,
62        document: impl Into<String>,
63        schemas: I,
64    ) -> Self
65    where
66        I: IntoIterator<Item = (N, B)>,
67        N: Into<String>,
68        B: Into<Vec<u8>>,
69    {
70        Self {
71            document_name: document_name.into(),
72            document: document.into(),
73            schemas: schemas
74                .into_iter()
75                .map(|(name, bytes)| (name.into(), bytes.into()))
76                .collect(),
77        }
78    }
79
80    /// Returns the document's original filename, extension included.
81    #[must_use]
82    pub fn document_name(&self) -> &str {
83        &self.document_name
84    }
85
86    /// Returns the authored AWL source text, byte-identical to what was
87    /// compiled.
88    #[must_use]
89    pub fn document(&self) -> &str {
90        &self.document
91    }
92
93    /// Returns the imported schema files keyed by their document-relative
94    /// path, which is the path to stage each file at before re-checking the
95    /// document.
96    #[must_use]
97    pub const fn schemas(&self) -> &BTreeMap<String, Vec<u8>> {
98        &self.schemas
99    }
100}