1#![allow(missing_docs)]
15
16use crate::error::{Error, Result};
17use crate::ir::{NodeId, ProvEntry, Provenance};
18use crate::layout::{DecodeOpts, Meta};
19use crate::validate::Validated;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub struct NodeView {
24 pub id: NodeId,
25 pub kind: u8,
26 pub flags: u8,
27 pub aux: u32,
28 pub a: u64,
29 pub b: u64,
30 pub c: u64,
31}
32
33impl NodeView {
34 pub fn kind_name(&self) -> &'static str {
35 node_kind_name(self.kind)
36 }
37
38 pub fn count(&self) -> u64 {
40 match self.kind {
41 7 | 8 | 14 | 20 => self.b,
42 _ => 0,
43 }
44 }
45}
46
47#[derive(Debug, Clone, Copy)]
49pub struct InfinityView<'a> {
50 validated: Validated<'a>,
51}
52
53impl<'a> InfinityView<'a> {
54 pub fn new(buf: &'a [u8], limits: crate::layout::Limits) -> Result<Self> {
56 let opts = DecodeOpts {
57 limits,
58 verify_hash: true,
59 verify_canonical: false,
60 };
61 Ok(Self {
62 validated: Validated::new(buf, opts)?,
63 })
64 }
65
66 pub fn with_opts(buf: &'a [u8], opts: DecodeOpts) -> Result<Self> {
68 Ok(Self {
69 validated: Validated::new(buf, opts)?,
70 })
71 }
72
73 pub fn from_validated(validated: Validated<'a>) -> Self {
75 Self { validated }
76 }
77
78 pub fn validated(&self) -> &Validated<'a> {
79 &self.validated
80 }
81
82 pub fn buf(&self) -> &'a [u8] {
83 self.validated.buf()
84 }
85
86 pub fn meta(&self) -> Meta {
87 self.validated.meta()
88 }
89
90 pub fn content_hash(&self) -> [u8; 32] {
91 self.validated.header().content_hash
92 }
93
94 pub fn content_hash_hex(&self) -> String {
95 crate::ir::hash_hex(&self.content_hash())
96 }
97
98 pub fn node_count(&self) -> u32 {
99 self.validated.node_count()
100 }
101
102 pub fn root(&self) -> Result<Option<NodeId>> {
103 self.validated.root()
104 }
105
106 pub fn bindings(&self) -> Result<Vec<(&'a str, NodeId)>> {
107 self.validated.bindings()
108 }
109
110 pub fn annotations(&self) -> Result<Vec<(NodeId, u32, u32)>> {
111 let mut out = Vec::new();
112 for index in 0..self
113 .validated
114 .span(crate::layout::Section::Annotations)
115 .count
116 {
117 let (node, kind, a, _b) = self.validated.annotation(index)?;
118 out.push((NodeId(node), kind, a));
119 }
120 Ok(out)
121 }
122
123 pub fn provenance(&self) -> Result<Option<Provenance>> {
124 self.validated.provenance()
125 }
126
127 pub fn node(&self, id: NodeId) -> Result<NodeView> {
129 let rec = self.validated.node(id)?;
130 Ok(NodeView {
131 id,
132 kind: rec.kind,
133 flags: rec.flags,
134 aux: rec.aux,
135 a: rec.a,
136 b: rec.b,
137 c: rec.c,
138 })
139 }
140
141 pub fn string(&self, id: u32) -> Result<&'a str> {
143 self.validated.string(id)
144 }
145
146 pub fn blob(&self, id: u32) -> Result<&'a [u8]> {
148 self.validated.blob(id)
149 }
150
151 pub fn node_string_id(&self, id: NodeId) -> Result<Option<u32>> {
153 let node = self.node(id)?;
154 Ok(match node.kind {
155 4 | 13 | 23 => Some(node.aux),
156 _ => None,
157 })
158 }
159
160 pub fn primary_string(&self, id: NodeId) -> Result<Option<&'a str>> {
162 match self.node_string_id(id)? {
163 Some(sid) => Ok(Some(self.string(sid)?)),
164 None => Ok(None),
165 }
166 }
167
168 pub fn children(&self, id: NodeId) -> Result<Vec<NodeId>> {
170 let node = self.node(id)?;
171 let mut out = Vec::new();
172 match node.kind {
173 6 => out.push(NodeId(node.aux)),
174 7 => {
175 for offset in node.a..node.a + node.b {
176 out.push(NodeId(self.validated.child(offset as u32)?));
177 }
178 }
179 8 | 20 => {
180 for offset in node.a..node.a + node.b {
181 out.push(self.validated.field(offset as u32)?.1);
182 }
183 }
184 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 24 => {
185 let rec = self.validated.node(id)?;
186 for child in self.validated.node_children(id.0, &rec)? {
187 out.push(NodeId(child));
188 }
189 }
190 _ => {}
191 }
192 Ok(out)
193 }
194
195 pub fn fields(&self, id: NodeId) -> Result<Vec<(&'a str, NodeId)>> {
197 let node = self.node(id)?;
198 if node.kind != 8 && node.kind != 20 {
199 return Err(Error::Node {
200 id: id.0,
201 reason: "not a table node",
202 });
203 }
204 let mut out = Vec::with_capacity(node.b as usize);
205 for offset in node.a..node.a + node.b {
206 let (name, child) = self.validated.field(offset as u32)?;
207 out.push((self.string(name)?, child));
208 }
209 Ok(out)
210 }
211
212 pub fn dependents(&self, id: NodeId) -> Result<Vec<NodeId>> {
214 let mut out = Vec::new();
215 for (from, to) in self.edges()? {
216 if from == id {
217 out.push(to);
218 }
219 }
220 out.sort_unstable();
221 out.dedup();
222 Ok(out)
223 }
224
225 pub fn dependencies(&self, id: NodeId) -> Result<Vec<NodeId>> {
227 let mut out = self.children(id)?;
228 out.sort_unstable();
229 out.dedup();
230 Ok(out)
231 }
232
233 pub fn edges(&self) -> Result<Vec<(NodeId, NodeId)>> {
235 let mut out = Vec::new();
236 for index in 0..self.validated.span(crate::layout::Section::Edges).count {
237 let (from, to) = self.validated.edge(index)?;
238 out.push((NodeId(from), NodeId(to)));
239 }
240 Ok(out)
241 }
242
243 pub fn provenance_entries(&self) -> Result<Vec<(String, ProvEntry)>> {
250 Ok(self
251 .validated
252 .provenance()?
253 .map(|prov| {
254 prov.entries
255 .into_iter()
256 .map(|entry| (entry.key.clone(), entry))
257 .collect()
258 })
259 .unwrap_or_default())
260 }
261}
262
263pub const fn node_kind_name(kind: u8) -> &'static str {
265 match kind {
266 0 => "Null",
267 1 => "Bool",
268 2 => "Int",
269 3 => "Float",
270 4 => "Str",
271 5 => "DurationMs",
272 6 => "Quantity",
273 7 => "Array",
274 8 => "Table",
275 9 => "Secret",
276 10 => "SecretRef",
277 11 => "Ref",
278 12 => "Env",
279 13 => "Ident",
280 14 => "Interpolate",
281 15 => "Binary",
282 16 => "Unary",
283 17 => "Constrained",
284 18 => "Patch",
285 19 => "SchemaField",
286 20 => "SchemaTable",
287 21 => "SchemaArray",
288 22 => "Semantic",
289 23 => "Blob",
290 24 => "ContentAddressed",
291 _ => "Unknown",
292 }
293}