#![allow(missing_docs)]
use crate::error::{Error, Result};
use crate::ir::{NodeId, ProvEntry, Provenance};
use crate::layout::{DecodeOpts, Meta};
use crate::validate::Validated;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NodeView {
pub id: NodeId,
pub kind: u8,
pub flags: u8,
pub aux: u32,
pub a: u64,
pub b: u64,
pub c: u64,
}
impl NodeView {
pub fn kind_name(&self) -> &'static str {
node_kind_name(self.kind)
}
pub fn count(&self) -> u64 {
match self.kind {
7 | 8 | 14 | 20 => self.b,
_ => 0,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct InfinityView<'a> {
validated: Validated<'a>,
}
impl<'a> InfinityView<'a> {
pub fn new(buf: &'a [u8], limits: crate::layout::Limits) -> Result<Self> {
let opts = DecodeOpts {
limits,
verify_hash: true,
verify_canonical: false,
};
Ok(Self {
validated: Validated::new(buf, opts)?,
})
}
pub fn with_opts(buf: &'a [u8], opts: DecodeOpts) -> Result<Self> {
Ok(Self {
validated: Validated::new(buf, opts)?,
})
}
pub fn from_validated(validated: Validated<'a>) -> Self {
Self { validated }
}
pub fn validated(&self) -> &Validated<'a> {
&self.validated
}
pub fn buf(&self) -> &'a [u8] {
self.validated.buf()
}
pub fn meta(&self) -> Meta {
self.validated.meta()
}
pub fn content_hash(&self) -> [u8; 32] {
self.validated.header().content_hash
}
pub fn content_hash_hex(&self) -> String {
crate::ir::hash_hex(&self.content_hash())
}
pub fn node_count(&self) -> u32 {
self.validated.node_count()
}
pub fn root(&self) -> Result<Option<NodeId>> {
self.validated.root()
}
pub fn bindings(&self) -> Result<Vec<(&'a str, NodeId)>> {
self.validated.bindings()
}
pub fn annotations(&self) -> Result<Vec<(NodeId, u32, u32)>> {
let mut out = Vec::new();
for index in 0..self
.validated
.span(crate::layout::Section::Annotations)
.count
{
let (node, kind, a, _b) = self.validated.annotation(index)?;
out.push((NodeId(node), kind, a));
}
Ok(out)
}
pub fn provenance(&self) -> Result<Option<Provenance>> {
self.validated.provenance()
}
pub fn node(&self, id: NodeId) -> Result<NodeView> {
let rec = self.validated.node(id)?;
Ok(NodeView {
id,
kind: rec.kind,
flags: rec.flags,
aux: rec.aux,
a: rec.a,
b: rec.b,
c: rec.c,
})
}
pub fn string(&self, id: u32) -> Result<&'a str> {
self.validated.string(id)
}
pub fn blob(&self, id: u32) -> Result<&'a [u8]> {
self.validated.blob(id)
}
pub fn node_string_id(&self, id: NodeId) -> Result<Option<u32>> {
let node = self.node(id)?;
Ok(match node.kind {
4 | 13 | 23 => Some(node.aux),
_ => None,
})
}
pub fn primary_string(&self, id: NodeId) -> Result<Option<&'a str>> {
match self.node_string_id(id)? {
Some(sid) => Ok(Some(self.string(sid)?)),
None => Ok(None),
}
}
pub fn children(&self, id: NodeId) -> Result<Vec<NodeId>> {
let node = self.node(id)?;
let mut out = Vec::new();
match node.kind {
6 => out.push(NodeId(node.aux)),
7 => {
for offset in node.a..node.a + node.b {
out.push(NodeId(self.validated.child(offset as u32)?));
}
}
8 | 20 => {
for offset in node.a..node.a + node.b {
out.push(self.validated.field(offset as u32)?.1);
}
}
10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 24 => {
let rec = self.validated.node(id)?;
for child in self.validated.node_children(id.0, &rec)? {
out.push(NodeId(child));
}
}
_ => {}
}
Ok(out)
}
pub fn fields(&self, id: NodeId) -> Result<Vec<(&'a str, NodeId)>> {
let node = self.node(id)?;
if node.kind != 8 && node.kind != 20 {
return Err(Error::Node {
id: id.0,
reason: "not a table node",
});
}
let mut out = Vec::with_capacity(node.b as usize);
for offset in node.a..node.a + node.b {
let (name, child) = self.validated.field(offset as u32)?;
out.push((self.string(name)?, child));
}
Ok(out)
}
pub fn dependents(&self, id: NodeId) -> Result<Vec<NodeId>> {
let mut out = Vec::new();
for (from, to) in self.edges()? {
if from == id {
out.push(to);
}
}
out.sort_unstable();
out.dedup();
Ok(out)
}
pub fn dependencies(&self, id: NodeId) -> Result<Vec<NodeId>> {
let mut out = self.children(id)?;
out.sort_unstable();
out.dedup();
Ok(out)
}
pub fn edges(&self) -> Result<Vec<(NodeId, NodeId)>> {
let mut out = Vec::new();
for index in 0..self.validated.span(crate::layout::Section::Edges).count {
let (from, to) = self.validated.edge(index)?;
out.push((NodeId(from), NodeId(to)));
}
Ok(out)
}
pub fn provenance_entries(&self) -> Result<Vec<(String, ProvEntry)>> {
Ok(self
.validated
.provenance()?
.map(|prov| {
prov.entries
.into_iter()
.map(|entry| (entry.key.clone(), entry))
.collect()
})
.unwrap_or_default())
}
}
pub const fn node_kind_name(kind: u8) -> &'static str {
match kind {
0 => "Null",
1 => "Bool",
2 => "Int",
3 => "Float",
4 => "Str",
5 => "DurationMs",
6 => "Quantity",
7 => "Array",
8 => "Table",
9 => "Secret",
10 => "SecretRef",
11 => "Ref",
12 => "Env",
13 => "Ident",
14 => "Interpolate",
15 => "Binary",
16 => "Unary",
17 => "Constrained",
18 => "Patch",
19 => "SchemaField",
20 => "SchemaTable",
21 => "SchemaArray",
22 => "Semantic",
23 => "Blob",
24 => "ContentAddressed",
_ => "Unknown",
}
}