oxedyne/fe2o3/fe2o3_sbj/examples/gen_demo.rs
6.5 KiB, 3 runs
created by r1870400018:21942, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | //! Writes the demo oxeweb document: one signed SBJ file, for every renderer to read. |
| 2 | //! |
| 3 | //! There is exactly one demo document, and both engines read it. Kiln renders it to pixels natively |
| 4 | //! and the browser renders it to DOM through WebAssembly, from these same bytes. That is what makes |
| 5 | //! the two comparable: a difference between them is a difference between the renderers, not between |
| 6 | //! two documents that happened to look alike. |
| 7 | //! |
| 8 | //! Run with `cargo run -p oxedyne_fe2o3_sbj --example gen_demo -- <path>`. |
| 9 | |
| 10 | use oxedyne_fe2o3_sbj::{ |
| 11 | doc, |
| 12 | kinds::NodeKind, |
| 13 | }; |
| 14 | |
| 15 | use oxedyne_fe2o3_core::prelude::*; |
| 16 | use oxedyne_fe2o3_crypto::sign::SignatureScheme; |
| 17 | use oxedyne_fe2o3_jdat::{ |
| 18 | prelude::*, |
| 19 | usr::UsrKindId, |
| 20 | }; |
| 21 | |
| 22 | /// The time the demo document is signed at, fixed so that a rebuild changes only the signature. |
| 23 | const TIME: u64 = 1_752_500_000_000; |
| 24 | |
| 25 | /// The user kind identifier of a node kind: its wire code, its label, and the shape of its payload. |
| 26 | fn ukid(kind: NodeKind) -> UsrKindId { |
| 27 | let payload = if kind.payload_is_str() { |
| 28 | Kind::Str |
| 29 | } else { |
| 30 | Kind::Map |
| 31 | }; |
| 32 | UsrKindId::new(kind.code(), Some(&fmt!("sbj_{}", kind.label())), Some(payload)) |
| 33 | } |
| 34 | |
| 35 | /// A node: a kind code, then its payload. |
| 36 | fn node(kind: NodeKind, payload: Dat) -> Dat { |
| 37 | Dat::Usr(ukid(kind), Some(Box::new(payload))) |
| 38 | } |
| 39 | |
| 40 | /// A text run, the one node whose payload is a bare string. |
| 41 | fn text(s: &str) -> Dat { |
| 42 | node(NodeKind::Text, Dat::Str(s.to_string())) |
| 43 | } |
| 44 | |
| 45 | /// A payload map. |
| 46 | fn map(pairs: Vec<(&str, Dat)>) -> Dat { |
| 47 | let mut m = DaticleMap::new(); |
| 48 | for (k, v) in pairs { |
| 49 | m.insert(Dat::Str(k.to_string()), v); |
| 50 | } |
| 51 | Dat::Map(m) |
| 52 | } |
| 53 | |
| 54 | /// The demo document, exercising every kind the vocabulary holds. |
| 55 | pub fn tree() -> Dat { |
| 56 | let tree = node(NodeKind::Doc, map(vec![ |
| 57 | ("title", Dat::Str("Style without a cascade".to_string())), |
| 58 | ("lang", Dat::Str("en".to_string())), |
| 59 | ("styles", map(vec![ |
| 60 | ("callout", map(vec![ |
| 61 | ("bg", Dat::Str("muted".to_string())), |
| 62 | ("pad", Dat::U8(3)), |
| 63 | ])), |
| 64 | ("centred", map(vec![ |
| 65 | ("align", Dat::Str("center".to_string())), |
| 66 | ("fill", Dat::Str("muted".to_string())), |
| 67 | ])), |
| 68 | ("flush", map(vec![ |
| 69 | ("align", Dat::Str("justify".to_string())), |
| 70 | ])), |
| 71 | ])), |
| 72 | ("children", Dat::List(vec![ |
| 73 | |
| 74 | node(NodeKind::Heading, map(vec![ |
| 75 | ("level", Dat::U8(1)), |
| 76 | ("children", Dat::List(vec![text("Style without a cascade")])), |
| 77 | ])), |
| 78 | |
| 79 | node(NodeKind::Para, map(vec![ |
| 80 | ("style", Dat::Str("flush".to_string())), |
| 81 | ("children", Dat::List(vec![ |
| 82 | text("The oxeweb replaces the web's cascade with "), |
| 83 | node(NodeKind::Emph, map(vec![ |
| 84 | ("strong", Dat::Bool(false)), |
| 85 | ("children", Dat::List(vec![text("locality")])), |
| 86 | ])), |
| 87 | text(". A node names a style; the style is defined once, in the document's \ |
| 88 | style table; and a short inherited set flows down the tree. No rule \ |
| 89 | reaches across the document, so a style error cannot escape the node \ |
| 90 | that made it. This paragraph is long enough that it must wrap, which \ |
| 91 | is the whole point of it."), |
| 92 | ])), |
| 93 | ])), |
| 94 | |
| 95 | node(NodeKind::Para, map(vec![ |
| 96 | ("children", Dat::List(vec![ |
| 97 | text("Emphasis can be "), |
| 98 | node(NodeKind::Emph, map(vec![ |
| 99 | ("strong", Dat::Bool(true)), |
| 100 | ("children", Dat::List(vec![text("strong")])), |
| 101 | ])), |
| 102 | text(", and a link points at "), |
| 103 | node(NodeKind::Link, map(vec![ |
| 104 | ("to", map(vec![("name", Dat::Str("news.cricket".to_string()))])), |
| 105 | ("children", Dat::List(vec![text("a name, not a location")])), |
| 106 | ])), |
| 107 | text("."), |
| 108 | ])), |
| 109 | ])), |
| 110 | |
| 111 | node(NodeKind::Boxx, map(vec![ |
| 112 | ("style", Dat::Str("callout".to_string())), |
| 113 | ("children", Dat::List(vec![ |
| 114 | node(NodeKind::Para, map(vec![ |
| 115 | ("children", Dat::List(vec![ |
| 116 | text("Reader preferences are applied after author styles, and \ |
| 117 | always win."), |
| 118 | ])), |
| 119 | ])), |
| 120 | ])), |
| 121 | ])), |
| 122 | |
| 123 | node(NodeKind::Heading, map(vec![ |
| 124 | ("level", Dat::U8(2)), |
| 125 | ("children", Dat::List(vec![text("What the format holds")])), |
| 126 | ])), |
| 127 | |
| 128 | node(NodeKind::List, map(vec![ |
| 129 | ("ordered", Dat::Bool(false)), |
| 130 | ("children", Dat::List(vec![ |
| 131 | node(NodeKind::Item, map(vec![ |
| 132 | ("children", Dat::List(vec![ |
| 133 | node(NodeKind::Para, map(vec![ |
| 134 | ("children", Dat::List(vec![ |
| 135 | text("Thirteen node kinds, and no more."), |
| 136 | ])), |
| 137 | ])), |
| 138 | ])), |
| 139 | ])), |
| 140 | node(NodeKind::Item, map(vec![ |
| 141 | ("children", Dat::List(vec![ |
| 142 | node(NodeKind::Para, map(vec![ |
| 143 | ("children", Dat::List(vec![ |
| 144 | text("Semantic colours and scale steps, never pixels."), |
| 145 | ])), |
| 146 | ])), |
| 147 | ])), |
| 148 | ])), |
| 149 | node(NodeKind::Item, map(vec![ |
| 150 | ("children", Dat::List(vec![ |
| 151 | node(NodeKind::Para, map(vec![ |
| 152 | ("children", Dat::List(vec![ |
| 153 | text("An address that is a hash of what it addresses."), |
| 154 | ])), |
| 155 | ])), |
| 156 | ])), |
| 157 | ])), |
| 158 | ])), |
| 159 | ])), |
| 160 | |
| 161 | node(NodeKind::Quote, map(vec![ |
| 162 | ("cite", Dat::Str("SPEC.md §6".to_string())), |
| 163 | ("children", Dat::List(vec![ |
| 164 | node(NodeKind::Para, map(vec![ |
| 165 | ("children", Dat::List(vec![ |
| 166 | text("There is no repair, no quirks mode, and no best effort. The \ |
| 167 | web gave that up in 1993 and spent thirty years paying for it."), |
| 168 | ])), |
| 169 | ])), |
| 170 | ])), |
| 171 | ])), |
| 172 | |
| 173 | node(NodeKind::Code, map(vec![ |
| 174 | ("lang", Dat::Str("jdat".to_string())), |
| 175 | ("text", Dat::Str( |
| 176 | "(box|{\n \"style\": \"callout\",\n \"children\": [...],\n})".to_string(), |
| 177 | )), |
| 178 | ])), |
| 179 | |
| 180 | node(NodeKind::Image, map(vec![ |
| 181 | ("hash", Dat::from([0x9fu8; 32])), |
| 182 | ("alt", Dat::Str("A diagram this reader has no copy of.".to_string())), |
| 183 | ])), |
| 184 | |
| 185 | // Mixed direction, resolved by the bidi algorithm and reordered by rule L2. |
| 186 | node(NodeKind::Para, map(vec![ |
| 187 | ("style", Dat::Str("centred".to_string())), |
| 188 | ("children", Dat::List(vec![ |
| 189 | text("Arabic runs the other way: مرحبا بالعالم — and back to English."), |
| 190 | ])), |
| 191 | ])), |
| 192 | ])), |
| 193 | ])); |
| 194 | tree |
| 195 | } |
| 196 | |
| 197 | fn main() -> Outcome<()> { |
| 198 | let args: Vec<String> = std::env::args().collect(); |
| 199 | let path = match args.get(1) { |
| 200 | Some(p) => p.clone(), |
| 201 | None => return Err(err!( |
| 202 | "Give the path to write the document to: \ |
| 203 | `cargo run -p sbj --example gen_demo -- <path>`."; |
| 204 | Invalid, Input, Missing)), |
| 205 | }; |
| 206 | |
| 207 | let signer = SignatureScheme::new_ed25519(); |
| 208 | let bytes = res!(doc::write(&tree(), "oxeweb/doc/0", &signer, TIME)); |
| 209 | |
| 210 | // It must read back the way a reader would, or it is not a document, it is a file. |
| 211 | res!(doc::read(&bytes)); |
| 212 | |
| 213 | if let Some(dir) = std::path::Path::new(&path).parent() { |
| 214 | res!(std::fs::create_dir_all(dir)); |
| 215 | } |
| 216 | res!(std::fs::write(&path, &bytes)); |
| 217 | println!("Wrote {} ({} bytes), verified.", path, bytes.len()); |
| 218 | Ok(()) |
| 219 | } |