1use std::collections::HashMap;
68
69use bytes::Bytes;
70use ndn_packet::{Name, NameComponent};
71
72pub const LVS_VERSION: u64 = 0x0001_1000;
77
78pub mod type_number {
80 pub const COMPONENT_VALUE: u64 = 0x21;
81 pub const PATTERN_TAG: u64 = 0x23;
82 pub const NODE_ID: u64 = 0x25;
83 pub const USER_FN_ID: u64 = 0x27;
84 pub const IDENTIFIER: u64 = 0x29;
85 pub const USER_FN_CALL: u64 = 0x31;
86 pub const FN_ARGS: u64 = 0x33;
87 pub const CONS_OPTION: u64 = 0x41;
88 pub const CONSTRAINT: u64 = 0x43;
89 pub const VALUE_EDGE: u64 = 0x51;
90 pub const PATTERN_EDGE: u64 = 0x53;
91 pub const KEY_NODE_ID: u64 = 0x55;
92 pub const PARENT_ID: u64 = 0x57;
93 pub const VERSION: u64 = 0x61;
94 pub const NODE: u64 = 0x63;
95 pub const TAG_SYMBOL: u64 = 0x67;
96 pub const NAMED_PATTERN_NUM: u64 = 0x69;
97}
98
99#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
101pub enum LvsError {
102 #[error("truncated TLV: {0}")]
103 Truncated(&'static str),
104 #[error("TLV length mismatch at offset {offset}: claimed {claimed}, available {available}")]
105 LengthMismatch {
106 offset: usize,
107 claimed: usize,
108 available: usize,
109 },
110 #[error("unexpected TLV type 0x{actual:x}, expected 0x{expected:x}")]
111 UnexpectedType { actual: u64, expected: u64 },
112 #[error("unsupported LVS binary version 0x{actual:x} (expected 0x{expected:x})")]
113 UnsupportedVersion { actual: u64, expected: u64 },
114 #[error("node id {node_id} out of range (model has {n} nodes)")]
115 NodeIdOutOfRange { node_id: u64, n: usize },
116 #[error("node at index {idx} has id {id} (must equal its index)")]
117 NodeIdMismatch { idx: usize, id: u64 },
118 #[error("ConstraintOption must have exactly one of Value/Tag/UserFn")]
119 MalformedConstraintOption,
120 #[error("invalid UTF-8 in identifier")]
121 BadIdentifier,
122}
123
124#[derive(Debug, Clone)]
130pub struct LvsModel {
131 pub version: u64,
132 pub start_id: u64,
133 pub named_pattern_cnt: u64,
134 pub nodes: Vec<LvsNode>,
135 pub tag_symbols: Vec<LvsTagSymbol>,
136 uses_user_functions: bool,
140}
141
142#[derive(Debug, Clone)]
143pub struct LvsNode {
144 pub id: u64,
145 pub parent: Option<u64>,
146 pub rule_names: Vec<String>,
147 pub value_edges: Vec<LvsValueEdge>,
148 pub pattern_edges: Vec<LvsPatternEdge>,
149 pub sign_constraints: Vec<u64>,
150}
151
152#[derive(Debug, Clone)]
153pub struct LvsValueEdge {
154 pub dest: u64,
155 pub value: NameComponent,
160}
161
162#[derive(Debug, Clone)]
163pub struct LvsPatternEdge {
164 pub dest: u64,
165 pub tag: u64,
166 pub constraints: Vec<LvsConstraint>,
167}
168
169#[derive(Debug, Clone)]
172pub struct LvsConstraint {
173 pub options: Vec<LvsConstraintOption>,
174}
175
176#[derive(Debug, Clone)]
177pub enum LvsConstraintOption {
178 Value(NameComponent),
182 Tag(u64),
185 UserFn(LvsUserFnCall),
189}
190
191#[derive(Debug, Clone)]
192pub struct LvsUserFnCall {
193 pub fn_id: String,
194 pub args: Vec<LvsUserFnArg>,
195}
196
197#[derive(Debug, Clone)]
198pub enum LvsUserFnArg {
199 Value(NameComponent),
200 Tag(u64),
201}
202
203#[derive(Debug, Clone)]
204pub struct LvsTagSymbol {
205 pub tag: u64,
206 pub ident: String,
207}
208
209impl LvsModel {
210 pub fn decode(input: &[u8]) -> Result<Self, LvsError> {
216 let mut cursor = input;
217 let mut version: Option<u64> = None;
218 let mut start_id: Option<u64> = None;
219 let mut named_pattern_cnt: Option<u64> = None;
220 let mut nodes: Vec<LvsNode> = Vec::new();
221 let mut tag_symbols: Vec<LvsTagSymbol> = Vec::new();
222 let mut uses_user_functions = false;
223
224 while !cursor.is_empty() {
225 let (t, value, rest) = read_tlv(cursor)?;
226 cursor = rest;
227 match t {
228 type_number::VERSION => {
229 version = Some(read_uint(value)?);
230 }
231 type_number::NODE_ID => {
232 start_id = Some(read_uint(value)?);
233 }
234 type_number::NAMED_PATTERN_NUM => {
235 named_pattern_cnt = Some(read_uint(value)?);
236 }
237 type_number::NODE => {
238 let (node, node_uses_fn) = LvsNode::decode(value)?;
239 uses_user_functions |= node_uses_fn;
240 nodes.push(node);
241 }
242 type_number::TAG_SYMBOL => {
243 tag_symbols.push(LvsTagSymbol::decode(value)?);
244 }
245 _ => {}
247 }
248 }
249
250 let version = version.ok_or(LvsError::Truncated("missing Version"))?;
251 if version != LVS_VERSION {
252 return Err(LvsError::UnsupportedVersion {
253 actual: version,
254 expected: LVS_VERSION,
255 });
256 }
257 let start_id = start_id.ok_or(LvsError::Truncated("missing StartId"))?;
258 let named_pattern_cnt =
259 named_pattern_cnt.ok_or(LvsError::Truncated("missing NamedPatternCnt"))?;
260
261 for (idx, n) in nodes.iter().enumerate() {
263 if n.id as usize != idx {
264 return Err(LvsError::NodeIdMismatch { idx, id: n.id });
265 }
266 }
267 let n_nodes = nodes.len();
269 for node in &nodes {
270 for e in &node.value_edges {
271 if e.dest as usize >= n_nodes {
272 return Err(LvsError::NodeIdOutOfRange {
273 node_id: e.dest,
274 n: n_nodes,
275 });
276 }
277 }
278 for e in &node.pattern_edges {
279 if e.dest as usize >= n_nodes {
280 return Err(LvsError::NodeIdOutOfRange {
281 node_id: e.dest,
282 n: n_nodes,
283 });
284 }
285 }
286 for &sc in &node.sign_constraints {
287 if sc as usize >= n_nodes {
288 return Err(LvsError::NodeIdOutOfRange {
289 node_id: sc,
290 n: n_nodes,
291 });
292 }
293 }
294 }
295 if (start_id as usize) >= n_nodes && n_nodes > 0 {
296 return Err(LvsError::NodeIdOutOfRange {
297 node_id: start_id,
298 n: n_nodes,
299 });
300 }
301
302 Ok(Self {
303 version,
304 start_id,
305 named_pattern_cnt,
306 nodes,
307 tag_symbols,
308 uses_user_functions,
309 })
310 }
311
312 pub fn uses_user_functions(&self) -> bool {
319 self.uses_user_functions
320 }
321
322 fn walk(&self, name: &Name) -> Vec<(u64, HashMap<u64, NameComponent>)> {
327 let mut out = Vec::new();
328 if self.nodes.is_empty() {
329 return out;
330 }
331 let start = self.start_id;
332 let bindings: HashMap<u64, NameComponent> = HashMap::new();
333 self.walk_inner(start, name.components(), 0, bindings, &mut out);
334 out
335 }
336
337 fn walk_inner(
338 &self,
339 node_id: u64,
340 comps: &[NameComponent],
341 depth: usize,
342 bindings: HashMap<u64, NameComponent>,
343 out: &mut Vec<(u64, HashMap<u64, NameComponent>)>,
344 ) {
345 if depth == comps.len() {
346 out.push((node_id, bindings));
347 return;
348 }
349 let Some(node) = self.nodes.get(node_id as usize) else {
350 return;
351 };
352 let comp = &comps[depth];
353
354 for ve in &node.value_edges {
356 if &ve.value == comp {
357 self.walk_inner(ve.dest, comps, depth + 1, bindings.clone(), out);
358 }
359 }
360
361 for pe in &node.pattern_edges {
368 if self.pattern_edge_matches(pe, comp, &bindings) {
369 let mut new_bindings = bindings.clone();
370 new_bindings.insert(pe.tag, comp.clone());
371 self.walk_inner(pe.dest, comps, depth + 1, new_bindings, out);
372 }
373 }
374 }
375
376 fn pattern_edge_matches(
377 &self,
378 edge: &LvsPatternEdge,
379 comp: &NameComponent,
380 bindings: &HashMap<u64, NameComponent>,
381 ) -> bool {
382 edge.constraints.iter().all(|c| {
385 c.options
386 .iter()
387 .any(|opt| self.option_matches(opt, comp, bindings))
388 })
389 }
390
391 fn option_matches(
392 &self,
393 opt: &LvsConstraintOption,
394 comp: &NameComponent,
395 bindings: &HashMap<u64, NameComponent>,
396 ) -> bool {
397 match opt {
398 LvsConstraintOption::Value(v) => v == comp,
399 LvsConstraintOption::Tag(t) => bindings.get(t).is_some_and(|prev| prev == comp),
400 LvsConstraintOption::UserFn(_) => false,
402 }
403 }
404
405 pub fn check(&self, data_name: &Name, key_name: &Name) -> bool {
412 let data_endings = self.walk(data_name);
413 if data_endings.is_empty() {
414 return false;
415 }
416 let key_endings = self.walk(key_name);
417 if key_endings.is_empty() {
418 return false;
419 }
420 for (data_node_id, _data_bindings) in &data_endings {
421 let Some(node) = self.nodes.get(*data_node_id as usize) else {
422 continue;
423 };
424 if node.sign_constraints.is_empty() {
425 continue;
426 }
427 for (key_node_id, _) in &key_endings {
428 if node.sign_constraints.contains(key_node_id) {
429 return true;
430 }
431 }
432 }
433 false
434 }
435}
436
437impl LvsNode {
438 fn decode(input: &[u8]) -> Result<(Self, bool), LvsError> {
439 let mut cursor = input;
440 let mut id: Option<u64> = None;
441 let mut parent: Option<u64> = None;
442 let mut rule_names = Vec::new();
443 let mut value_edges = Vec::new();
444 let mut pattern_edges = Vec::new();
445 let mut sign_constraints = Vec::new();
446 let mut uses_user_functions = false;
447
448 while !cursor.is_empty() {
449 let (t, v, rest) = read_tlv(cursor)?;
450 cursor = rest;
451 match t {
452 type_number::NODE_ID => id = Some(read_uint(v)?),
453 type_number::PARENT_ID => parent = Some(read_uint(v)?),
454 type_number::IDENTIFIER => rule_names.push(read_string(v)?),
455 type_number::VALUE_EDGE => value_edges.push(LvsValueEdge::decode(v)?),
456 type_number::PATTERN_EDGE => {
457 let (edge, uses_fn) = LvsPatternEdge::decode(v)?;
458 uses_user_functions |= uses_fn;
459 pattern_edges.push(edge);
460 }
461 type_number::KEY_NODE_ID => sign_constraints.push(read_uint(v)?),
462 _ => {}
463 }
464 }
465
466 let id = id.ok_or(LvsError::Truncated("Node missing NodeId"))?;
467 Ok((
468 Self {
469 id,
470 parent,
471 rule_names,
472 value_edges,
473 pattern_edges,
474 sign_constraints,
475 },
476 uses_user_functions,
477 ))
478 }
479}
480
481impl LvsValueEdge {
482 fn decode(input: &[u8]) -> Result<Self, LvsError> {
483 let mut cursor = input;
484 let mut dest: Option<u64> = None;
485 let mut value: Option<NameComponent> = None;
486 while !cursor.is_empty() {
487 let (t, v, rest) = read_tlv(cursor)?;
488 cursor = rest;
489 match t {
490 type_number::NODE_ID => dest = Some(read_uint(v)?),
491 type_number::COMPONENT_VALUE => value = Some(parse_name_component(v)?),
492 _ => {}
493 }
494 }
495 Ok(Self {
496 dest: dest.ok_or(LvsError::Truncated("ValueEdge missing dest"))?,
497 value: value.ok_or(LvsError::Truncated("ValueEdge missing value"))?,
498 })
499 }
500}
501
502impl LvsPatternEdge {
503 fn decode(input: &[u8]) -> Result<(Self, bool), LvsError> {
504 let mut cursor = input;
505 let mut dest: Option<u64> = None;
506 let mut tag: Option<u64> = None;
507 let mut constraints = Vec::new();
508 let mut uses_user_functions = false;
509 while !cursor.is_empty() {
510 let (t, v, rest) = read_tlv(cursor)?;
511 cursor = rest;
512 match t {
513 type_number::NODE_ID => dest = Some(read_uint(v)?),
514 type_number::PATTERN_TAG => tag = Some(read_uint(v)?),
515 type_number::CONSTRAINT => {
516 let (c, uses_fn) = LvsConstraint::decode(v)?;
517 uses_user_functions |= uses_fn;
518 constraints.push(c);
519 }
520 _ => {}
521 }
522 }
523 Ok((
524 Self {
525 dest: dest.ok_or(LvsError::Truncated("PatternEdge missing dest"))?,
526 tag: tag.ok_or(LvsError::Truncated("PatternEdge missing tag"))?,
527 constraints,
528 },
529 uses_user_functions,
530 ))
531 }
532}
533
534impl LvsConstraint {
535 fn decode(input: &[u8]) -> Result<(Self, bool), LvsError> {
536 let mut cursor = input;
537 let mut options = Vec::new();
538 let mut uses_user_functions = false;
539 while !cursor.is_empty() {
540 let (t, v, rest) = read_tlv(cursor)?;
541 cursor = rest;
542 if t == type_number::CONS_OPTION {
543 let (opt, uses_fn) = LvsConstraintOption::decode(v)?;
544 uses_user_functions |= uses_fn;
545 options.push(opt);
546 }
547 }
548 Ok((Self { options }, uses_user_functions))
549 }
550}
551
552impl LvsConstraintOption {
553 fn decode(input: &[u8]) -> Result<(Self, bool), LvsError> {
554 let mut cursor = input;
555 let mut value: Option<NameComponent> = None;
556 let mut tag: Option<u64> = None;
557 let mut fn_call: Option<LvsUserFnCall> = None;
558
559 while !cursor.is_empty() {
560 let (t, v, rest) = read_tlv(cursor)?;
561 cursor = rest;
562 match t {
563 type_number::COMPONENT_VALUE => value = Some(parse_name_component(v)?),
564 type_number::PATTERN_TAG => tag = Some(read_uint(v)?),
565 type_number::USER_FN_CALL => fn_call = Some(LvsUserFnCall::decode(v)?),
566 _ => {}
567 }
568 }
569
570 let set_count = value.is_some() as u8 + tag.is_some() as u8 + fn_call.is_some() as u8;
571 if set_count != 1 {
572 return Err(LvsError::MalformedConstraintOption);
573 }
574
575 if let Some(v) = value {
576 Ok((Self::Value(v), false))
577 } else if let Some(t) = tag {
578 Ok((Self::Tag(t), false))
579 } else {
580 Ok((Self::UserFn(fn_call.unwrap()), true))
581 }
582 }
583}
584
585impl LvsUserFnCall {
586 fn decode(input: &[u8]) -> Result<Self, LvsError> {
587 let mut cursor = input;
588 let mut fn_id: Option<String> = None;
589 let mut args: Vec<LvsUserFnArg> = Vec::new();
590 while !cursor.is_empty() {
591 let (t, v, rest) = read_tlv(cursor)?;
592 cursor = rest;
593 match t {
594 type_number::USER_FN_ID => fn_id = Some(read_string(v)?),
595 type_number::FN_ARGS => args.push(LvsUserFnArg::decode(v)?),
596 _ => {}
597 }
598 }
599 Ok(Self {
600 fn_id: fn_id.ok_or(LvsError::Truncated("UserFnCall missing FnId"))?,
601 args,
602 })
603 }
604}
605
606impl LvsUserFnArg {
607 fn decode(input: &[u8]) -> Result<Self, LvsError> {
608 let mut cursor = input;
609 let mut value: Option<NameComponent> = None;
610 let mut tag: Option<u64> = None;
611 while !cursor.is_empty() {
612 let (t, v, rest) = read_tlv(cursor)?;
613 cursor = rest;
614 match t {
615 type_number::COMPONENT_VALUE => value = Some(parse_name_component(v)?),
616 type_number::PATTERN_TAG => tag = Some(read_uint(v)?),
617 _ => {}
618 }
619 }
620 if let Some(v) = value {
621 Ok(Self::Value(v))
622 } else if let Some(t) = tag {
623 Ok(Self::Tag(t))
624 } else {
625 Err(LvsError::Truncated("UserFnArg empty"))
626 }
627 }
628}
629
630impl LvsTagSymbol {
631 fn decode(input: &[u8]) -> Result<Self, LvsError> {
632 let mut cursor = input;
633 let mut tag: Option<u64> = None;
634 let mut ident: Option<String> = None;
635 while !cursor.is_empty() {
636 let (t, v, rest) = read_tlv(cursor)?;
637 cursor = rest;
638 match t {
639 type_number::PATTERN_TAG => tag = Some(read_uint(v)?),
640 type_number::IDENTIFIER => ident = Some(read_string(v)?),
641 _ => {}
642 }
643 }
644 Ok(Self {
645 tag: tag.ok_or(LvsError::Truncated("TagSymbol missing tag"))?,
646 ident: ident.ok_or(LvsError::Truncated("TagSymbol missing ident"))?,
647 })
648 }
649}
650
651fn read_tlv(input: &[u8]) -> Result<(u64, &[u8], &[u8]), LvsError> {
655 let (t, tn) = ndn_tlv::read_varu64(input).map_err(|_| LvsError::Truncated("TLV type"))?;
656 let (l, ln) =
657 ndn_tlv::read_varu64(&input[tn..]).map_err(|_| LvsError::Truncated("TLV length"))?;
658 let header_len = tn + ln;
659 let total = header_len
660 .checked_add(l as usize)
661 .ok_or(LvsError::Truncated("TLV length overflow"))?;
662 if total > input.len() {
663 return Err(LvsError::LengthMismatch {
664 offset: 0,
665 claimed: total,
666 available: input.len(),
667 });
668 }
669 Ok((t, &input[header_len..total], &input[total..]))
670}
671
672fn read_uint(v: &[u8]) -> Result<u64, LvsError> {
674 match v.len() {
675 1 => Ok(v[0] as u64),
676 2 => Ok(u16::from_be_bytes(v.try_into().unwrap()) as u64),
677 4 => Ok(u32::from_be_bytes(v.try_into().unwrap()) as u64),
678 8 => Ok(u64::from_be_bytes(v.try_into().unwrap())),
679 _ => Err(LvsError::Truncated("uint: unexpected length")),
680 }
681}
682
683fn read_string(v: &[u8]) -> Result<String, LvsError> {
684 std::str::from_utf8(v)
685 .map(|s| s.to_owned())
686 .map_err(|_| LvsError::BadIdentifier)
687}
688
689fn parse_name_component(value: &[u8]) -> Result<NameComponent, LvsError> {
700 let (t, tn) =
701 ndn_tlv::read_varu64(value).map_err(|_| LvsError::Truncated("NameComponent type"))?;
702 let (l, ln) = ndn_tlv::read_varu64(&value[tn..])
703 .map_err(|_| LvsError::Truncated("NameComponent length"))?;
704 let start = tn + ln;
705 let end = start
706 .checked_add(l as usize)
707 .ok_or(LvsError::Truncated("NameComponent length overflow"))?;
708 if end > value.len() {
709 return Err(LvsError::LengthMismatch {
710 offset: 0,
711 claimed: end,
712 available: value.len(),
713 });
714 }
715 Ok(NameComponent::new(
716 t,
717 Bytes::copy_from_slice(&value[start..end]),
718 ))
719}
720
721#[cfg(test)]
722mod tests {
723 use super::*;
724 use bytes::BytesMut;
725
726 fn write_tlv(buf: &mut BytesMut, t: u64, value: &[u8]) {
733 use ndn_tlv::TlvWriter;
734 let mut w = TlvWriter::new();
735 w.write_tlv(t, value);
736 buf.extend_from_slice(&w.finish());
737 }
738
739 fn encode_generic_nc(bytes: &[u8]) -> Vec<u8> {
742 let mut out = Vec::with_capacity(2 + bytes.len());
743 out.push(0x08);
744 out.push(bytes.len() as u8);
745 out.extend_from_slice(bytes);
746 out
747 }
748
749 fn write_component_value_tlv(buf: &mut BytesMut, bytes: &[u8]) {
753 let nc = encode_generic_nc(bytes);
754 write_tlv(buf, type_number::COMPONENT_VALUE, &nc);
755 }
756
757 fn uint_be(value: u64) -> Vec<u8> {
758 if value <= u8::MAX as u64 {
759 vec![value as u8]
760 } else if value <= u16::MAX as u64 {
761 (value as u16).to_be_bytes().to_vec()
762 } else if value <= u32::MAX as u64 {
763 (value as u32).to_be_bytes().to_vec()
764 } else {
765 value.to_be_bytes().to_vec()
766 }
767 }
768
769 fn write_uint_tlv(buf: &mut BytesMut, t: u64, value: u64) {
770 let be = uint_be(value);
771 write_tlv(buf, t, &be);
772 }
773
774 fn build_hierarchical_fixture() -> Vec<u8> {
785 let mut out = BytesMut::new();
786 write_uint_tlv(&mut out, type_number::VERSION, LVS_VERSION);
788 write_uint_tlv(&mut out, type_number::NODE_ID, 0); write_uint_tlv(&mut out, type_number::NAMED_PATTERN_NUM, 0);
790
791 {
793 let mut node = BytesMut::new();
794 write_uint_tlv(&mut node, type_number::NODE_ID, 0);
795 {
797 let mut ve = BytesMut::new();
798 write_uint_tlv(&mut ve, type_number::NODE_ID, 1);
799 write_component_value_tlv(&mut ve, b"app");
800 write_tlv(&mut node, type_number::VALUE_EDGE, &ve);
801 }
802 {
804 let mut ve = BytesMut::new();
805 write_uint_tlv(&mut ve, type_number::NODE_ID, 2);
806 write_component_value_tlv(&mut ve, b"key");
807 write_tlv(&mut node, type_number::VALUE_EDGE, &ve);
808 }
809 write_tlv(&mut out, type_number::NODE, &node);
810 }
811
812 {
814 let mut node = BytesMut::new();
815 write_uint_tlv(&mut node, type_number::NODE_ID, 1);
816 write_uint_tlv(&mut node, type_number::PARENT_ID, 0);
817 write_uint_tlv(&mut node, type_number::KEY_NODE_ID, 2);
818 write_tlv(&mut out, type_number::NODE, &node);
819 }
820
821 {
823 let mut node = BytesMut::new();
824 write_uint_tlv(&mut node, type_number::NODE_ID, 2);
825 write_uint_tlv(&mut node, type_number::PARENT_ID, 0);
826 write_tlv(&mut out, type_number::NODE, &node);
827 }
828
829 out.to_vec()
830 }
831
832 fn comp(s: &'static str) -> NameComponent {
833 NameComponent::generic(Bytes::from_static(s.as_bytes()))
834 }
835
836 fn name(parts: &[&'static str]) -> Name {
837 Name::from_components(parts.iter().map(|p| comp(p)))
838 }
839
840 #[test]
841 fn decode_hierarchical_fixture() {
842 let wire = build_hierarchical_fixture();
843 let model = LvsModel::decode(&wire).expect("decode");
844 assert_eq!(model.version, LVS_VERSION);
845 assert_eq!(model.start_id, 0);
846 assert_eq!(model.named_pattern_cnt, 0);
847 assert_eq!(model.nodes.len(), 3);
848 assert_eq!(model.nodes[0].value_edges.len(), 2);
849 assert_eq!(model.nodes[1].sign_constraints, vec![2]);
850 assert!(!model.uses_user_functions());
851 }
852
853 #[test]
854 fn hierarchical_allows_app_signed_by_key() {
855 let model = LvsModel::decode(&build_hierarchical_fixture()).unwrap();
856 assert!(model.check(&name(&["app"]), &name(&["key"])));
857 }
858
859 #[test]
860 fn hierarchical_rejects_wrong_key_name() {
861 let model = LvsModel::decode(&build_hierarchical_fixture()).unwrap();
862 assert!(!model.check(&name(&["app"]), &name(&["other"])));
863 }
864
865 #[test]
866 fn hierarchical_rejects_unknown_data_name() {
867 let model = LvsModel::decode(&build_hierarchical_fixture()).unwrap();
868 assert!(!model.check(&name(&["stranger"]), &name(&["key"])));
869 }
870
871 fn build_pattern_fixture() -> Vec<u8> {
894 let mut out = BytesMut::new();
895 write_uint_tlv(&mut out, type_number::VERSION, LVS_VERSION);
896 write_uint_tlv(&mut out, type_number::NODE_ID, 0);
897 write_uint_tlv(&mut out, type_number::NAMED_PATTERN_NUM, 1);
898
899 {
901 let mut node = BytesMut::new();
902 write_uint_tlv(&mut node, type_number::NODE_ID, 0);
903 let mut ve = BytesMut::new();
904 write_uint_tlv(&mut ve, type_number::NODE_ID, 1);
905 write_component_value_tlv(&mut ve, b"sensor");
906 write_tlv(&mut node, type_number::VALUE_EDGE, &ve);
907 write_tlv(&mut out, type_number::NODE, &node);
908 }
909
910 {
912 let mut node = BytesMut::new();
913 write_uint_tlv(&mut node, type_number::NODE_ID, 1);
914 write_uint_tlv(&mut node, type_number::PARENT_ID, 0);
915
916 {
918 let mut pe = BytesMut::new();
919 write_uint_tlv(&mut pe, type_number::NODE_ID, 2);
920 write_uint_tlv(&mut pe, type_number::PATTERN_TAG, 1);
921 write_tlv(&mut node, type_number::PATTERN_EDGE, &pe);
922 }
923 {
937 let mut pe = BytesMut::new();
938 write_uint_tlv(&mut pe, type_number::NODE_ID, 3);
939 write_uint_tlv(&mut pe, type_number::PATTERN_TAG, 1);
940 write_tlv(&mut node, type_number::PATTERN_EDGE, &pe);
941 }
942 write_tlv(&mut out, type_number::NODE, &node);
943 }
944
945 {
947 let mut node = BytesMut::new();
948 write_uint_tlv(&mut node, type_number::NODE_ID, 2);
949 write_uint_tlv(&mut node, type_number::PARENT_ID, 1);
950 write_uint_tlv(&mut node, type_number::KEY_NODE_ID, 4);
951 write_tlv(&mut out, type_number::NODE, &node);
952 }
953
954 {
956 let mut node = BytesMut::new();
957 write_uint_tlv(&mut node, type_number::NODE_ID, 3);
958 write_uint_tlv(&mut node, type_number::PARENT_ID, 1);
959 let mut ve = BytesMut::new();
960 write_uint_tlv(&mut ve, type_number::NODE_ID, 4);
961 write_component_value_tlv(&mut ve, b"KEY");
962 write_tlv(&mut node, type_number::VALUE_EDGE, &ve);
963 write_tlv(&mut out, type_number::NODE, &node);
964 }
965
966 {
968 let mut node = BytesMut::new();
969 write_uint_tlv(&mut node, type_number::NODE_ID, 4);
970 write_uint_tlv(&mut node, type_number::PARENT_ID, 3);
971 write_tlv(&mut out, type_number::NODE, &node);
972 }
973
974 out.to_vec()
975 }
976
977 #[test]
978 fn pattern_fixture_allows_data_signed_by_key() {
979 let model = LvsModel::decode(&build_pattern_fixture()).unwrap();
980 assert!(model.check(
982 &name(&["sensor", "temp"]),
983 &name(&["sensor", "temp", "KEY"])
984 ));
985 }
986
987 #[test]
988 fn pattern_fixture_rejects_shorter_key() {
989 let model = LvsModel::decode(&build_pattern_fixture()).unwrap();
990 assert!(!model.check(&name(&["sensor", "temp"]), &name(&["sensor", "temp"])));
991 }
992
993 #[test]
994 fn pattern_fixture_rejects_wrong_root() {
995 let model = LvsModel::decode(&build_pattern_fixture()).unwrap();
996 assert!(!model.check(&name(&["other", "temp"]), &name(&["sensor", "temp", "KEY"])));
997 }
998
999 #[test]
1002 fn unsupported_version_errors() {
1003 let mut out = BytesMut::new();
1004 write_uint_tlv(&mut out, type_number::VERSION, 0xDEADBEEF);
1005 write_uint_tlv(&mut out, type_number::NODE_ID, 0);
1006 write_uint_tlv(&mut out, type_number::NAMED_PATTERN_NUM, 0);
1007 assert!(matches!(
1008 LvsModel::decode(&out),
1009 Err(LvsError::UnsupportedVersion { .. })
1010 ));
1011 }
1012
1013 #[test]
1016 fn user_function_schema_parses_and_flags() {
1017 let mut out = BytesMut::new();
1018 write_uint_tlv(&mut out, type_number::VERSION, LVS_VERSION);
1019 write_uint_tlv(&mut out, type_number::NODE_ID, 0);
1020 write_uint_tlv(&mut out, type_number::NAMED_PATTERN_NUM, 1);
1021
1022 {
1024 let mut node = BytesMut::new();
1025 write_uint_tlv(&mut node, type_number::NODE_ID, 0);
1026 let mut pe = BytesMut::new();
1027 write_uint_tlv(&mut pe, type_number::NODE_ID, 1);
1028 write_uint_tlv(&mut pe, type_number::PATTERN_TAG, 1);
1029 {
1030 let mut cons = BytesMut::new();
1031 {
1032 let mut opt = BytesMut::new();
1033 let mut call = BytesMut::new();
1034 write_tlv(&mut call, type_number::USER_FN_ID, b"$regex");
1035 {
1036 let mut arg = BytesMut::new();
1037 write_component_value_tlv(&mut arg, b"^[0-9]+$");
1038 write_tlv(&mut call, type_number::FN_ARGS, &arg);
1039 }
1040 write_tlv(&mut opt, type_number::USER_FN_CALL, &call);
1041 write_tlv(&mut cons, type_number::CONS_OPTION, &opt);
1042 }
1043 write_tlv(&mut pe, type_number::CONSTRAINT, &cons);
1044 }
1045 write_tlv(&mut node, type_number::PATTERN_EDGE, &pe);
1046 write_tlv(&mut out, type_number::NODE, &node);
1047 }
1048 {
1050 let mut node = BytesMut::new();
1051 write_uint_tlv(&mut node, type_number::NODE_ID, 1);
1052 write_uint_tlv(&mut node, type_number::PARENT_ID, 0);
1053 write_tlv(&mut out, type_number::NODE, &node);
1054 }
1055
1056 let model = LvsModel::decode(&out).expect("decode");
1057 assert!(
1058 model.uses_user_functions(),
1059 "user-fn schema must flag uses_user_functions"
1060 );
1061 assert!(!model.check(&name(&["123"]), &name(&["123"])));
1063 }
1064}