cddl_cat/
validate.rs

1//! This module contains code to validate serialized data.
2//!
3//! More precisely, it validates data that can be represented by [`Value`] trees.
4
5use crate::context::LookupContext;
6use crate::ivt::*;
7use crate::util::{mismatch, ValidateError, ValidateResult};
8use crate::value::Value;
9use std::collections::BTreeMap; // used in Value::Map
10use std::collections::HashMap;
11use std::collections::VecDeque;
12use std::convert::TryInto;
13use std::mem::discriminant;
14
15// A map from generic parameter name to the type being used here.
16#[derive(Clone, Debug, Default)]
17struct GenericMap<'a> {
18    map: HashMap<String, &'a Node>,
19    // Because we captured this map at a previous time, we may need to look up
20    // generic types from that previous context.  We carry a copy of that
21    // Context with us to do those lookups.
22    past_ctx: Option<&'a Context<'a>>,
23}
24
25#[derive(Clone)]
26struct Context<'a> {
27    lookup: &'a dyn LookupContext,
28    generic_map: GenericMap<'a>,
29    depth: u32,
30}
31
32impl std::fmt::Debug for Context<'_> {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        f.debug_struct("Context")
35            .field("generic_map", &self.generic_map)
36            .finish()
37    }
38}
39
40struct NodeContext<'a> {
41    node: &'a Node,
42    ctx: Context<'a>,
43}
44
45impl<'a> Context<'a> {
46    // Set a maximum depth, to avoid infinite recursion in the case of
47    // circular rule references.
48    const MAX_DEPTH: u32 = 50;
49
50    fn inc_depth(&self) -> TempResult<u32> {
51        if self.depth >= Self::MAX_DEPTH {
52            Err(ValidateError::Structural("hit recursion limit".into()))
53        } else {
54            Ok(self.depth + 1)
55        }
56    }
57
58    // `lookup_rule` will first do a search for a local generic parameter name
59    // first, followed by a lookup for a rule by that name.
60
61    // To give an example:
62    //     IP = [u8, u8, u8, u8]
63    //     PORT = u16
64    //     socket = [IP, PORT]
65    //     conn<IP> = [name, socket, IP] # This is the generic parm IP not the rule IP.
66    //
67    // While validating "conn" we have a Context with a generic mapping for "IP".
68    // As soon as we traverse into "socket", we need for there to be a new context,
69    // where no "IP" exists (so we'll do the rule lookup instead).
70    //
71    fn lookup_rule(&'a self, rule: &'a Rule) -> TempResult<NodeContext<'a>> {
72        // First, check to see if the "rule name" is actually a generic parameter.
73        // TODO: this would be a lot easier if this were pre-processed by the flattener
74        // so that "rule lookup" and "generic type lookup" were two separate Node variants.
75        let generic_node: Option<&'a Node> = self.generic_map.map.get(&rule.name).cloned();
76        if let Some(node) = generic_node {
77            // If we stored a past_ctx along with the generic args, then pass that
78            // context along with the node that is substituting for this generic
79            // parameter name.  Otherwise, return a new blank Context.
80            let ctx = match self.generic_map.past_ctx {
81                Some(ctx) => ctx.clone(),
82                None => self.blank()?,
83            };
84            return Ok(NodeContext { node, ctx });
85        }
86
87        let rule_def: &RuleDef = self.lookup.lookup_rule(&rule.name)?;
88
89        // Create a new context containing a new generic parameter map.
90        let ctx = self.derive(rule_def, rule)?;
91
92        Ok(NodeContext {
93            node: &rule_def.node,
94            ctx,
95        })
96    }
97
98    // Create a new blank Context (with no parameter map)
99    fn blank(&self) -> TempResult<Context<'a>> {
100        Ok(Context {
101            lookup: self.lookup,
102            generic_map: GenericMap::default(),
103            depth: self.inc_depth()?,
104        })
105    }
106
107    // Create a new Context, with optional generic parameter map.
108    fn derive(&'a self, rule_def: &'a RuleDef, rule: &'a Rule) -> TempResult<Context<'a>> {
109        let parms_len = rule_def.generic_parms.len();
110        let args_len = rule.generic_args.len();
111        if parms_len != args_len {
112            // Wrong number of generic arguments
113            return Err(ValidateError::GenericError);
114        }
115
116        // Zip the two Vecs:
117        // 1. rule_def.generic_parms
118        // 2. rule.generic_args
119        // and put them into a HashMap so we can do lookups from parm -> arg.
120        let map: HashMap<String, &'a Node> = rule_def
121            .generic_parms
122            .iter()
123            .cloned()
124            .zip(rule.generic_args.iter())
125            .collect();
126
127        let generic_map = GenericMap {
128            map,
129            past_ctx: Some(self),
130        };
131
132        Ok(Context {
133            lookup: self.lookup,
134            generic_map,
135            depth: self.inc_depth()?,
136        })
137    }
138}
139
140pub(crate) fn do_validate(
141    value: &Value,
142    rule_def: &RuleDef,
143    ctx: &dyn LookupContext,
144) -> ValidateResult {
145    // If the rule_def passed in requires generic parameters, we should
146    // return an error, because we don't have any way to specify them.
147    if !rule_def.generic_parms.is_empty() {
148        return Err(ValidateError::GenericError);
149    }
150
151    let ctx = Context {
152        lookup: ctx,
153        generic_map: GenericMap::default(),
154        depth: 0,
155    };
156    let node = &rule_def.node;
157    validate(value, node, &ctx)
158}
159
160type ValueMap = BTreeMap<Value, Value>;
161
162// A Result that returns some temporary value.
163type TempResult<T> = Result<T, ValidateError>;
164
165/// This struct allows us to maintain a map that is consumed during validation.
166struct WorkingMap {
167    map: ValueMap,
168    // A stack of lists; each list contains maybe-discarded elements,
169    // in (key, value) form.
170    snaps: VecDeque<VecDeque<(Value, Value)>>,
171}
172
173impl WorkingMap {
174    /// Makes a copy of an existing map's table.
175    fn new(value_map: &ValueMap) -> WorkingMap {
176        WorkingMap {
177            map: value_map.clone(),
178            snaps: VecDeque::new(),
179        }
180    }
181
182    // When we start speculatively matching map elements (e.g. in a Choice
183    // or Occur containing groups), we may fail the match partway through, and
184    // need to rewind to the most recent snapshot.
185    //
186    // It's possible for nested snapshots to exist; for example if we have a
187    // group-of-choices nested inside a group-of-choices.
188    //
189    // If one array is nested inside another, the inner array will get its
190    // own WorkingArray so snapshots aren't necessary in that case.
191    fn snapshot(&mut self) {
192        self.snaps.push_back(VecDeque::new());
193    }
194
195    // Restore the map to the point when we last called snapshot()
196    fn rewind(&mut self) {
197        // If validate code is implemented correctly, then unwrap() should
198        // never panic.
199        let mut top_snap = self.snaps.pop_back().unwrap();
200        // Drain the elements (order not important), and insert them back into
201        // the working map.
202        self.map.extend(top_snap.drain(..));
203    }
204
205    // We completed a match, so we can retire the most recent snapshot.
206    fn commit(&mut self) {
207        // If validate code is implemented correctly, then unwrap() should
208        // never panic.
209        // This throws away the list that was popped; those values were
210        // successfully matched and are no longer needed.
211        self.snaps.pop_back().unwrap();
212    }
213
214    // Peek at the value correspending to a given key (if any)
215    fn peek_at(&self, key: &Value) -> Option<&Value> {
216        self.map.get(key)
217    }
218
219    // Remove a value from the working map.
220    // If there is an active snapshot, stash the key/value pair there until
221    // we're certain we've matched the entire group.
222    fn remove(&mut self, key: &Value) {
223        // If validate code is implemented correctly, then unwrap() should
224        // never panic (we've already peeked at this value in order to match
225        // it.)
226        let value = self.map.remove(key).unwrap();
227        // If there is a current snapshot, preserve this element
228        // for later rewind.
229        if let Some(snap) = self.snaps.back_mut() {
230            snap.push_back((key.clone(), value));
231        }
232    }
233}
234
235/// This struct allows us to maintain a copy of an array that is consumed
236/// during validation.
237#[derive(Debug)]
238struct WorkingArray {
239    // The elements in the Value Array
240    array: VecDeque<Value>,
241    // A stack of lists; each list contains maybe-discarded elements.
242    snaps: VecDeque<VecDeque<Value>>,
243}
244
245impl WorkingArray {
246    /// Makes a copy of an existing map's table.
247    fn new(array: &[Value]) -> WorkingArray {
248        let deque: VecDeque<Value> = array.iter().cloned().collect();
249        WorkingArray {
250            array: deque,
251            snaps: VecDeque::new(),
252        }
253    }
254
255    // When we start speculatively matching array elements (e.g. in a Choice
256    // or Occur containing groups), we may fail the match partway through, and
257    // need to rewind to the most recent snapshot.
258    //
259    // It's possible for nested snapshots to exist; for example if we have a
260    // group-of-choices nested inside a group-of-choices.
261    //
262    // If one array is nested inside another, the inner array will get its
263    // own WorkingArray so snapshots aren't necessary in that case.
264    fn snapshot(&mut self) {
265        let new_snap: VecDeque<Value> = VecDeque::new();
266        self.snaps.push_back(new_snap);
267    }
268
269    // Restore the array to the point when we last called snapshot()
270    fn rewind(&mut self) {
271        // If validate code is implemented correctly, then unwrap() should
272        // never panic.
273        let mut top_snap = self.snaps.pop_back().unwrap();
274        // drain the elements in LIFO order, and push them back into
275        // the working array.
276        for element in top_snap.drain(..).rev() {
277            self.array.push_front(element);
278        }
279    }
280
281    // We completed a match, so we can retire the most recent snapshot.
282    fn commit(&mut self) {
283        // If validate code is implemented correctly, then unwrap() should
284        // never panic.
285        // This throws away the list that was popped; those values were
286        // successfully matched and are no longer needed.
287        self.snaps.pop_back().unwrap();
288    }
289
290    // Peek at the front of the working array.
291    fn peek_front(&self) -> Option<&Value> {
292        self.array.front()
293    }
294
295    // Remove an element from the working array.
296    // If there is an active snapshot, stash the element there until we're
297    // certain we've matched the entire group.
298    fn pop_front(&mut self) {
299        // If validate code is implemented correctly, then unwrap() should
300        // never panic (we've already peeked at this value in order to match
301        // it.)
302        let element = self.array.pop_front().unwrap();
303        // If there is a current snapshot, preserve this element
304        // for later rewind.
305        if let Some(snap) = self.snaps.back_mut() {
306            snap.push_back(element);
307        }
308    }
309}
310
311// Prevent warnings if both serde_cbor and serde_json are disabled.
312#[allow(dead_code)]
313
314// This is the main validation dispatch function.
315// It tries to match a Node and a Value, recursing as needed.
316fn validate(value: &Value, node: &Node, ctx: &Context) -> ValidateResult {
317    match node {
318        Node::Literal(l) => validate_literal(l, value),
319        Node::PreludeType(p) => validate_prelude_type(*p, value),
320        Node::Choice(c) => validate_choice(c, value, ctx),
321        Node::Map(m) => validate_map(m, value, ctx),
322        Node::Array(a) => validate_array(a, value, ctx),
323        Node::Rule(r) => validate_rule(r, value, ctx),
324        Node::Group(g) => validate_standalone_group(g, value, ctx),
325        Node::KeyValue(_) => Err(ValidateError::Structural("unexpected KeyValue".into())),
326        Node::Occur(_) => Err(ValidateError::Structural("unexpected Occur".into())),
327        Node::Unwrap(_) => Err(ValidateError::Structural("unexpected Unwrap".into())),
328        Node::Range(r) => validate_range(r, value, ctx),
329        Node::Control(ctl) => validate_control(ctl, value, ctx),
330        Node::Choiceify(r) => validate_choiceify(r, value, ctx),
331        Node::ChoiceifyInline(a) => validate_choiceify_inline(a, value, ctx),
332    }
333}
334
335// Perform map key search.
336// Some keys (literal values) can be found with a fast search, while
337// others may require a linear search.
338fn validate_map_key<'a>(
339    value_map: &'a mut WorkingMap,
340    node: &Node,
341    ctx: &Context,
342) -> TempResult<(Value, &'a Value)> {
343    match node {
344        Node::Literal(l) => map_search_literal(l, value_map),
345        _ => map_search(node, value_map, ctx),
346    }
347}
348
349/// Validate a `Choice` containing an arbitrary number of "option" nodes.
350///
351/// If any of the options matches, this validation is successful.
352fn validate_choice(choice: &Choice, value: &Value, ctx: &Context) -> ValidateResult {
353    for node in &choice.options {
354        match validate(value, node, ctx) {
355            Ok(()) => {
356                return Ok(());
357            }
358            Err(e) => {
359                // Only fail if the error is considered fatal.
360                // Otherwise, we'll keep trying other options.
361                if e.is_fatal() {
362                    return Err(e);
363                }
364            }
365        }
366    }
367    let expected = format!("choice of {}", choice.options.len());
368    Err(mismatch(expected))
369}
370
371/// Validate a `Rule` reference
372///
373/// Seek out the right `Node` and `Context`, and recurse.
374fn validate_rule(rule: &Rule, value: &Value, ctx: &Context) -> ValidateResult {
375    let answer = ctx.lookup_rule(rule)?;
376    validate(value, answer.node, &answer.ctx)
377}
378
379/// Create a `Value` from a `Literal`.
380impl From<&Literal> for Value {
381    fn from(l: &Literal) -> Value {
382        match l {
383            Literal::Bool(b) => Value::Bool(*b),
384            Literal::Int(i) => Value::Integer(*i),
385            Literal::Float(f) => Value::from_float(*f),
386            Literal::Text(t) => Value::Text(t.clone()),
387            Literal::Bytes(b) => Value::Bytes(b.clone()),
388        }
389    }
390}
391
392fn validate_literal(literal: &Literal, value: &Value) -> ValidateResult {
393    if *value == Value::from(literal) {
394        return Ok(());
395    }
396    Err(mismatch(format!("{}", literal)))
397}
398
399// Find a specific key in the map and return that key plus a reference to its value.
400fn map_search_literal<'a>(
401    literal: &Literal,
402    working_map: &'a mut WorkingMap,
403) -> TempResult<(Value, &'a Value)> {
404    let search_key = Value::from(literal);
405    match working_map.peek_at(&search_key) {
406        Some(val) => Ok((search_key, val)),
407        None => {
408            // We didn't find the key; return an error
409            Err(mismatch(format!("map{{{}}}", literal)))
410        }
411    }
412}
413
414// Iterate over each key in the working map, looking for a match.
415// If we find a match, return a copy of the key, and a reference to the value.
416// This is less efficient than map_search_literal.
417fn map_search<'a>(
418    node: &Node,
419    working_map: &'a mut WorkingMap,
420    ctx: &Context,
421) -> TempResult<(Value, &'a Value)> {
422    for (key, value) in &working_map.map {
423        let attempt = validate(key, node, ctx);
424        if attempt.is_ok() {
425            return Ok((key.clone(), value));
426        }
427    }
428    // We searched all the keys without finding a match.  Validation fails.
429    Err(mismatch(format!("map{{{}}}", node)))
430}
431
432// Note `ty` is passed by value because clippy says it's only 1 byte.
433fn validate_prelude_type(ty: PreludeType, value: &Value) -> ValidateResult {
434    match (ty, value) {
435        (PreludeType::Any, _) => Ok(()),
436        (PreludeType::Nil, Value::Null) => Ok(()),
437        (PreludeType::Nil, _) => Err(mismatch("nil")),
438        (PreludeType::Bool, Value::Bool(_)) => Ok(()),
439        (PreludeType::Bool, _) => Err(mismatch("bool")),
440        (PreludeType::Int, Value::Integer(_)) => Ok(()),
441        (PreludeType::Int, _) => Err(mismatch("int")),
442        (PreludeType::Uint, Value::Integer(x)) if *x >= 0 => Ok(()),
443        (PreludeType::Uint, _) => Err(mismatch("uint")),
444        (PreludeType::Nint, Value::Integer(x)) if *x < 0 => Ok(()),
445        (PreludeType::Nint, _) => Err(mismatch("nint")),
446        (PreludeType::Float, Value::Float(_)) => Ok(()),
447        (PreludeType::Float, _) => Err(mismatch("float")),
448        (PreludeType::Tstr, Value::Text(_)) => Ok(()),
449        (PreludeType::Tstr, _) => Err(mismatch("tstr")),
450        (PreludeType::Bstr, Value::Bytes(_)) => Ok(()),
451        (PreludeType::Bstr, _) => Err(mismatch("bstr")),
452    }
453}
454
455// FIXME: should this be combined with Map handling?
456fn validate_array(ar: &Array, value: &Value, ctx: &Context) -> ValidateResult {
457    match value {
458        Value::Array(a) => validate_array_part2(ar, a, ctx),
459        _ => Err(mismatch("array")),
460    }
461}
462
463fn validate_array_part2(ar: &Array, value_array: &[Value], ctx: &Context) -> ValidateResult {
464    // Strategy for validating an array:
465    // 1. We assume that the code that constructed the IVT Array placed the
466    //    members in matching order (literals first, more general types at the
467    //    end) so that we consume IVT Array members in order without worrying
468    //    about non-deterministic results.
469    // 2. Make a mutable working copy of the Value::Array contents
470    // 3. Iterate over the IVT Array, searching the working copy for a
471    //    matching key.
472    // 4. If a match is found, remove the value from our working copy.
473    // 6. If the IVT member can consume multiple values, repeat the search for
474    //    this key.
475    // 7. If a match is not found and the member is optional (or we've already
476    //    consumed an acceptable number of keys), continue to the next IVT
477    //    member.
478    // 8. If the member is not found and we haven't consumed the expected
479    //    number of values, return an error.
480
481    let mut working_array = WorkingArray::new(value_array);
482
483    for member in &ar.members {
484        validate_array_member(member, &mut working_array, ctx)?;
485    }
486    if working_array.array.is_empty() {
487        Ok(())
488    } else {
489        // If the working map isn't empty, that means we had some extra values
490        // that didn't match anything.
491        // FIXME: Should this be a unique error type?
492        Err(mismatch("shorter array"))
493    }
494}
495
496fn validate_array_member(
497    member: &Node,
498    working_array: &mut WorkingArray,
499    ctx: &Context,
500) -> ValidateResult {
501    match member {
502        // FIXME: does it make sense for this to destructure & dispatch
503        // each Node type here?  Is there any way to make this generic?
504        Node::Occur(o) => validate_array_occur(o, working_array, ctx),
505        Node::KeyValue(kv) => {
506            // The key is ignored.  Validate the value only.
507            // FIXME: should we try to use the key to provide a more
508            // useful error message?
509            validate_array_value(&kv.value, working_array, ctx)
510        }
511        Node::Rule(r) => {
512            // FIXME: This seems like a gross hack.  We need to dereference
513            // the rule here, because if we drop to the bottom and call
514            // validate_array_value() then we lose our ability to "see
515            // through" KeyValue and Group nodes while remembering that we are
516            // in an array context (with a particular working copy).
517            // BUG: Choice nodes will have the same problem.
518
519            let answer = ctx.lookup_rule(r)?;
520            validate_array_member(answer.node, working_array, &answer.ctx)
521        }
522        Node::Unwrap(r) => {
523            // Like Rule, we are dereferencing the Rule by hand here so that
524            // we can "see through" to the underlying data without forgetting
525            // we were in an array context.
526            let answer = ctx.lookup_rule(r)?;
527            validate_array_unwrap(answer.node, working_array, &answer.ctx)
528        }
529        Node::Choice(c) => {
530            // We need to explore each of the possible choices.
531            // We can't use validate_array_value() because we'll lose our
532            // array context.
533            for option in &c.options {
534                match validate_array_member(option, working_array, ctx) {
535                    Ok(()) => {
536                        return Ok(());
537                    }
538                    Err(e) => {
539                        // Only fail if the error is considered fatal.
540                        // Otherwise, we'll keep trying other options.
541                        if e.is_fatal() {
542                            return Err(e);
543                        }
544                    }
545                }
546            }
547            // None of the choices worked.
548            let expected = format!("choice of {}", c.options.len());
549            Err(mismatch(expected))
550        }
551        Node::Group(g) => {
552            // As we call validate_array_member, we don't know how many items
553            // it might speculatively pop from the list.  So we'll take a snapshot
554            // now and commit our changes if we match successfully (and roll them
555            // back if it fails).
556            working_array.snapshot();
557
558            // Recurse into each member of the group.
559            for group_member in &g.members {
560                match validate_array_member(group_member, working_array, ctx) {
561                    Ok(_) => {
562                        // So far so good...
563                    }
564                    Err(e) => {
565                        // Since we failed to validate the entire group, rewind to our most
566                        // recent snapshot.  This may put values back into the array,
567                        // so they can be matched by whatever we try next (or trigger
568                        // an error if they aren't consumed by anything).
569                        working_array.rewind();
570                        return Err(e);
571                    }
572                }
573            }
574            // All group members validated Ok.
575            working_array.commit();
576            Ok(())
577        }
578        m => validate_array_value(m, working_array, ctx),
579    }
580}
581
582fn validate_array_unwrap(
583    node: &Node,
584    working_array: &mut WorkingArray,
585    ctx: &Context,
586) -> ValidateResult {
587    // After traversing an unwrap from inside an array, the next node must be an
588    // Array node too.
589    match node {
590        Node::Array(a) => {
591            // Recurse into each member of the unwrapped array.
592            for member in &a.members {
593                validate_array_member(member, working_array, ctx)?;
594            }
595            // All array members validated Ok.
596            Ok(())
597        }
598        _ => Err(mismatch("unwrap array")),
599    }
600}
601
602/// Validate an occurrence against a mutable working array.
603// FIXME: this is pretty similar to validate_map_occur; maybe they can be combined?
604fn validate_array_occur(
605    occur: &Occur,
606    working_array: &mut WorkingArray,
607    ctx: &Context,
608) -> ValidateResult {
609    let (lower_limit, upper_limit) = occur.limits();
610    let mut count: usize = 0;
611
612    loop {
613        match validate_array_member(&occur.node, working_array, ctx) {
614            Ok(_) => (),
615            Err(e) => {
616                if e.is_mismatch() {
617                    // Stop trying to match this occurrence.
618                    break;
619                }
620                // The error is something serious (e.g. MissingRule or
621                // Unsupported).  We should fail now and propagate that
622                // error upward.
623                return Err(e);
624            }
625        }
626        count += 1;
627        if count >= upper_limit {
628            // Stop matching; we've consumed the maximum number of this key.
629            break;
630        }
631    }
632    if count < lower_limit {
633        return Err(mismatch(format!("more array element [{}]", occur)));
634    }
635    Ok(())
636}
637
638/// Validate some node against a mutable working array.
639fn validate_array_value(
640    node: &Node,
641    working_array: &mut WorkingArray,
642    ctx: &Context,
643) -> ValidateResult {
644    match working_array.peek_front() {
645        Some(val) => {
646            validate(val, node, ctx)?;
647            // We had a successful match; remove the matched value.
648            working_array.pop_front();
649            Ok(())
650        }
651        None => Err(mismatch(format!("array element {}", node))),
652    }
653}
654
655fn validate_map(m: &Map, value: &Value, ctx: &Context) -> ValidateResult {
656    match value {
657        Value::Map(vm) => validate_map_part2(m, vm, ctx),
658        _ => Err(mismatch("map")),
659    }
660}
661
662fn validate_map_part2(m: &Map, value_map: &ValueMap, ctx: &Context) -> ValidateResult {
663    // Strategy for validating a map:
664    // 1. We assume that the code that constructed the IVT Map placed the keys
665    //    in matching order (literals first, more general types at the end) so
666    //    that we consume IVT Map keys in order without worrying about non-
667    //    deterministic results.
668    // 2. Make a mutable working copy of the Value::Map contents
669    // 3. Iterate over the IVT Map, searching the Value::Map for a matching key.
670    // 4. If a match is found, remove the key-value pair from our working copy.
671    // 5. Validate the key's corresponding value.
672    // 6. If the key can consume multiple values, repeat the search for this key.
673    // 7. If the key is not found and the key is optional (or we've already consumed
674    //    an acceptable number of keys), continue to the next key.
675    // 8. If the key is not found and we haven't consumed the expected number of
676    //    keys, return an error.
677
678    let mut working_map = WorkingMap::new(value_map);
679
680    for member in &m.members {
681        validate_map_member(member, &mut working_map, ctx).map_err(|e| {
682            // If a MapCut error pops out here, change it to a Mismatch, so that
683            // it can't cause trouble in nested maps.
684            e.erase_mapcut()
685        })?;
686    }
687    if working_map.map.is_empty() {
688        Ok(())
689    } else {
690        // If the working map isn't empty, that means we had some extra values
691        // that didn't match anything.
692        Err(mismatch("shorter map"))
693    }
694}
695
696fn validate_map_member(
697    member: &Node,
698    working_map: &mut WorkingMap,
699    ctx: &Context,
700) -> ValidateResult {
701    match member {
702        // FIXME: does it make sense for this to destructure & dispatch
703        // each Node type here?  Is there any way to make this generic?
704        Node::Occur(o) => validate_map_occur(o, working_map, ctx),
705        Node::KeyValue(kv) => validate_map_keyvalue(kv, working_map, ctx),
706        Node::Rule(r) => {
707            // We can't use the generic validate() here; we would forget that
708            // we were in a map context.  We need to punch down a level into
709            // the rule and match again.
710            let answer = ctx.lookup_rule(r)?;
711            validate_map_member(answer.node, working_map, &answer.ctx)
712        }
713        Node::Unwrap(r) => {
714            // Like Rule, we are dereferencing the Rule by hand here so that
715            // we can "see through" to the underlying data without forgetting
716            // we were in a map context.
717            let answer = ctx.lookup_rule(r)?;
718            validate_map_unwrap(answer.node, working_map, &answer.ctx)
719        }
720        Node::Group(g) => {
721            // As we call validate_array_member, we don't know how many items
722            // it might speculatively pop from the list.  So we'll take a
723            // snapshot now and commit our changes if we match successfully
724            // (and roll them back if it fails).
725            working_map.snapshot();
726
727            // Recurse into each member of the group.
728            for group_member in &g.members {
729                match validate_map_member(group_member, working_map, ctx) {
730                    Ok(_) => {
731                        // So far so good...
732                    }
733                    Err(e) => {
734                        // Since we failed to validate the entire group,
735                        // rewind to our most recent snapshot.  This may put
736                        // values back into the map, so they can be matched by
737                        // whatever we try next (or trigger an error if they
738                        // aren't consumed by anything).
739                        working_map.rewind();
740
741                        // Also forget any MapCut errors, so that a sibling
742                        // group may succeed where we failed.
743                        return Err(e.erase_mapcut());
744                    }
745                }
746            }
747            // All group members validated Ok.
748            working_map.commit();
749            Ok(())
750        }
751        Node::Choice(c) => validate_map_choice(&c.options, working_map, ctx),
752        Node::Choiceify(r) => validate_map_choiceify(r, working_map, ctx),
753        Node::ChoiceifyInline(a) => validate_map_choice(&a.members, working_map, ctx),
754
755        // I don't think any of these are possible using CDDL grammar.
756        Node::Literal(_) => Err(ValidateError::Structural("literal map member".into())),
757        Node::PreludeType(_) => Err(ValidateError::Structural("prelude type map member".into())),
758        Node::Map(_) => Err(ValidateError::Structural("map as map member".into())),
759        Node::Array(_) => Err(ValidateError::Structural("array as map member".into())),
760        Node::Range(_) => Err(ValidateError::Structural("range as map member".into())),
761        Node::Control(_) => Err(ValidateError::Structural("control op as map member".into())),
762    }
763}
764
765fn validate_map_choice(
766    options: &[Node],
767    working_map: &mut WorkingMap,
768    ctx: &Context,
769) -> ValidateResult {
770    // We need to explore each of the possible choices.
771    for option in options {
772        match validate_map_member(option, working_map, ctx) {
773            Ok(()) => {
774                return Ok(());
775            }
776            Err(e) => {
777                // We can keep trying other options as long as the
778                // error is a Mismatch, not a MapCut or something
779                // fatal.
780                if !e.is_mismatch() {
781                    return Err(e);
782                }
783            }
784        }
785    }
786    // None of the choices worked.
787    let expected = format!("choice of {}", options.len());
788    Err(mismatch(expected))
789}
790
791// TODO: this duplicates a lot of code from validate_choiceify_members. Merge them?
792fn validate_map_choiceify_members(
793    choices: &[Node],
794    working_map: &mut WorkingMap,
795    ctx: &Context,
796) -> ValidateResult {
797    // Iterate over the input nodes. We expect a list of KeyValue variants.
798    // For each KeyValue, extract its .value member and try to validate that.
799    // Because we are in a group context, referring to other groups by name is
800    // also allowed; we will transparently unwrap those (recursively).
801
802    for item in choices {
803        let validate_result = match item {
804            Node::KeyValue(kv) => {
805                // Even though we're in a map, the choicify operation
806                // throws away the keys on its immediate operand.
807                // validate against the value (which is presumably
808                // a group containing KeyValues)
809                validate_map_member(&kv.value, working_map, ctx)
810            }
811            Node::Rule(rule) => {
812                // A group may include another group by name.
813                validate_map_choiceify(rule, working_map, ctx)
814            }
815            _ => {
816                // The flatten code will simplify a key-less KeyValue
817                // to just a plain Node; handle that here.
818                validate_map_member(item, working_map, ctx)
819            }
820        };
821
822        // This part is the same as validate_map_choice().
823        // If we matched, return Ok immediately.
824        // If we didn't, keep searching (unless the error is not a mismatch).
825        match validate_result {
826            Ok(()) => {
827                return Ok(());
828            }
829            Err(e) => {
830                // We can keep trying other options as long as the
831                // error is a Mismatch, not a MapCut or something
832                // fatal.
833                if !e.is_mismatch() {
834                    return Err(e);
835                }
836            }
837        }
838    }
839    let expected = format!("choiceified group of {}", choices.len());
840    Err(mismatch(expected))
841}
842
843/// Validate a "choice-ified group" (the CDDL "&" operator)
844///
845/// Each value in the named group will be used as a possible choice.
846fn validate_map_choiceify(
847    rule: &Rule,
848    working_map: &mut WorkingMap,
849    ctx: &Context,
850) -> ValidateResult {
851    let NodeContext { node, ctx } = ctx.lookup_rule(rule)?;
852    match node {
853        Node::Group(g) => validate_map_choiceify_members(&g.members, working_map, &ctx),
854        Node::Rule(r) => validate_map_choiceify(r, working_map, &ctx),
855        _ => Err(ValidateError::Structural(
856            "improper map choiceify target".into(),
857        )),
858    }
859}
860
861fn validate_map_unwrap(node: &Node, working_map: &mut WorkingMap, ctx: &Context) -> ValidateResult {
862    // After traversing an unwrap from inside a map, the next node must be a
863    // Map node too.
864    match node {
865        Node::Map(m) => {
866            // Recurse into each member of the unwrapped array.
867            for member in &m.members {
868                validate_map_member(member, working_map, ctx)?;
869            }
870            // All array members validated Ok.
871            Ok(())
872        }
873        _ => Err(mismatch("unwrap map")),
874    }
875}
876
877/// Validate an occurrence against a mutable working map.
878fn validate_map_occur(
879    occur: &Occur,
880    working_map: &mut WorkingMap,
881    ctx: &Context,
882) -> ValidateResult {
883    let (lower_limit, upper_limit) = occur.limits();
884    let mut count: usize = 0;
885
886    loop {
887        match validate_map_member(&occur.node, working_map, ctx) {
888            Ok(_) => (),
889            Err(e) => {
890                if e.is_mismatch() {
891                    // Stop trying to match this occurrence.
892                    break;
893                }
894                // Either we got a MapCut error, or it's something even more
895                // serious (e.g. MissingRule or Unsupported).  We should fail
896                // now and propagate that error upward.
897                return Err(e);
898            }
899        }
900        count += 1;
901        if count >= upper_limit {
902            // Stop matching; we've consumed the maximum number of this key.
903            break;
904        }
905    }
906    if count < lower_limit {
907        // Read this format string as "{{" then "{}" then "}}"
908        // The first and last print a single brace; the value is in the
909        // middle, e.g "{foo}".
910        return Err(mismatch(format!("map{{{}}}]", occur)));
911    }
912    Ok(())
913}
914
915/// Validate a key-value pair against a mutable working map.
916fn validate_map_keyvalue(
917    kv: &KeyValue,
918    working_map: &mut WorkingMap,
919    ctx: &Context,
920) -> ValidateResult {
921    // CDDL syntax reminder:
922    //   a => b   ; non-cut
923    //   a ^ => b ; cut
924    //   a: b     ; cut
925    //
926    // If we're using "cut" semantics, a partial match (key matches + value
927    // mismatch) should force validation failure for the entire map.  We
928    // signal this to our caller with a MapCut error.
929    // If we're using "non-cut" semantics, a partial match will leave the
930    // key-value pair in place, in the hope it may match something else.
931
932    let key_node = &kv.key;
933    let val_node = &kv.value;
934    let cut = kv.cut;
935
936    // If we fail to validate a key, exit now with an error.
937    let (working_key, working_val) = validate_map_key(working_map, key_node, ctx)?;
938
939    // Match the value that was returned.
940    match validate(working_val, val_node, ctx) {
941        Ok(()) => {
942            working_map.remove(&working_key);
943            Ok(())
944        }
945        Err(e) => {
946            match (cut, e) {
947                (true, ValidateError::Mismatch(m)) => {
948                    // If "cut" semantics are in force, then rewrite Mismatch errors.
949                    // This allows special handling when nested inside Occur nodes.
950                    Err(ValidateError::MapCut(m))
951                }
952                (_, x) => Err(x),
953            }
954        }
955    }
956}
957
958fn validate_standalone_group(g: &Group, value: &Value, ctx: &Context) -> ValidateResult {
959    // Since we're not in an array or map context, it's not clear how we should
960    // validate a group containing multiple elements.  If we see one, return an
961    // error.
962    match g.members.len() {
963        1 => {
964            // Since our group has length 1, validate against that single element.
965            validate(value, &g.members[0], ctx)
966        }
967        _ => Err(ValidateError::Unsupported("standalone group".into())),
968    }
969}
970
971fn deref_range_rule(node: &Node, ctx: &Context) -> TempResult<Literal> {
972    match node {
973        Node::Literal(l) => Ok(l.clone()),
974        Node::Rule(r) => {
975            let answer = ctx.lookup_rule(r)?;
976            deref_range_rule(answer.node, &answer.ctx)
977        }
978        _ => Err(ValidateError::Structural(
979            "confusing type on range operator".into(),
980        )),
981    }
982}
983
984// Returns true if value is within range
985fn check_range<T: PartialOrd>(start: T, end: T, value: T, inclusive: bool) -> bool {
986    if value < start {
987        return false;
988    }
989    if inclusive {
990        value <= end
991    } else {
992        value < end
993    }
994}
995
996fn validate_range(range: &Range, value: &Value, ctx: &Context) -> ValidateResult {
997    // first dereference rules on start and end, if necessary.
998    let start = deref_range_rule(&range.start, ctx)?;
999    let end = deref_range_rule(&range.end, ctx)?;
1000
1001    match (&start, &end, &value) {
1002        (Literal::Int(i1), Literal::Int(i2), Value::Integer(v)) => {
1003            if check_range(i1, i2, v, range.inclusive) {
1004                Ok(())
1005            } else {
1006                Err(mismatch(format!("{}", range)))
1007            }
1008        }
1009        (Literal::Float(f1), Literal::Float(f2), Value::Float(v)) => {
1010            if check_range(f1, f2, &v.0, range.inclusive) {
1011                Ok(())
1012            } else {
1013                Err(mismatch(format!("{}", range)))
1014            }
1015        }
1016        _ => {
1017            if discriminant(&start) == discriminant(&end) {
1018                // The range types were the same, so this is just a mismatch.
1019                Err(mismatch(format!("{}", range)))
1020            } else {
1021                // The range types didn't agree; return an error that points the
1022                // finger at the CDDL instead.
1023                Err(ValidateError::Structural(
1024                    "mismatched types on range operator".into(),
1025                ))
1026            }
1027        }
1028    }
1029}
1030
1031// Follow a chain of Rule references until we reach a non-Rule node.
1032fn chase_rules<'a, F, R>(node: &'a Node, ctx: &'a Context<'a>, f: F) -> TempResult<R>
1033where
1034    F: Fn(&Node) -> TempResult<R>,
1035    R: 'static,
1036{
1037    if let Node::Rule(rule) = node {
1038        let answer = ctx.lookup_rule(rule)?;
1039        chase_rules(answer.node, &answer.ctx, f)
1040    } else {
1041        f(node)
1042    }
1043}
1044
1045fn validate_control(ctl: &Control, value: &Value, ctx: &Context) -> ValidateResult {
1046    match ctl {
1047        Control::Size(ctl_size) => validate_control_size(ctl_size, value, ctx),
1048        Control::Regexp(re) => validate_control_regexp(re, value),
1049        Control::Cbor(ctl_cbor) => validate_control_cbor(ctl_cbor, value, ctx),
1050    }
1051}
1052
1053#[cfg(not(feature = "serde_cbor"))]
1054fn validate_control_cbor(_ctl_cbor: &CtlOpCbor, _value: &Value, _ctx: &Context) -> ValidateResult {
1055    Err(ValidateError::Unsupported(
1056        "'.cbor' control operator; enable serde_cbor feature to support.".into(),
1057    ))
1058}
1059
1060#[cfg(feature = "serde_cbor")]
1061fn validate_control_cbor(ctl_cbor: &CtlOpCbor, value: &Value, ctx: &Context) -> ValidateResult {
1062    use serde_cbor::Value as CBOR_Value;
1063    use std::convert::TryFrom;
1064
1065    match value {
1066        Value::Bytes(bytes) => {
1067            let cbor_value: CBOR_Value = serde_cbor::from_slice(bytes)
1068                .map_err(|e| ValidateError::ValueError(format!("{}", e)))?;
1069
1070            let nested_value = Value::try_from(cbor_value)?;
1071
1072            validate(&nested_value, ctl_cbor.node.as_ref(), ctx)
1073        }
1074        _ => Err::<(), ValidateError>(mismatch("Bytes")),
1075    }
1076}
1077
1078fn validate_control_size(ctl: &CtlOpSize, value: &Value, ctx: &Context) -> ValidateResult {
1079    // Follow the chain of rules references until we wind up with a non-Rule node.
1080    let size: u64 = chase_rules(&ctl.size, ctx, |size_node| {
1081        // Compute the size in bytes
1082        match size_node {
1083            Node::Literal(Literal::Int(i)) => (*i).try_into().map_err(|_| {
1084                // Note the parser doesn't handle >64 bit positive integers.
1085                // Under normal circumstances, the only way this can occur is
1086                // when the limit is negative.
1087                let msg = format!("bad .size limit {}", i);
1088                ValidateError::Structural(msg)
1089            }),
1090            _ => {
1091                // Under normal circumstances this error is unreachable
1092                // because the flatten code will only allow literal integer sizes.
1093                let msg = format!("bad .size argument type ({})", size_node);
1094                Err(ValidateError::Structural(msg))
1095            }
1096        }
1097    })?;
1098
1099    chase_rules(&ctl.target, ctx, |target_node| {
1100        // Ensure that the target node evaluates to some type that is
1101        // compatible with the .size operator, and then validate the size limit.
1102        match target_node {
1103            Node::PreludeType(PreludeType::Uint) => validate_size_uint(size, value),
1104            Node::PreludeType(PreludeType::Tstr) => validate_size_tstr(size, value),
1105            Node::PreludeType(PreludeType::Bstr) => validate_size_bstr(size, value),
1106            _ => {
1107                let msg = format!("bad .size target type ({})", target_node);
1108
1109                Err(ValidateError::Structural(msg))
1110            }
1111        }
1112    })
1113}
1114
1115/// Validate the control operator "regexp"
1116///
1117/// `regexp` applies a regular expression to a text string.
1118///
1119fn validate_control_regexp(re: &CtlOpRegexp, value: &Value) -> ValidateResult {
1120    match value {
1121        Value::Text(text) => {
1122            if re.re.is_match(text) {
1123                Ok(())
1124            } else {
1125                Err(mismatch("regex mismatch"))
1126            }
1127        }
1128        _ => Err(mismatch("tstr")),
1129    }
1130}
1131
1132fn validate_size_uint(size: u64, value: &Value) -> ValidateResult {
1133    match value {
1134        Value::Integer(x) => {
1135            if *x < 0 {
1136                Err(mismatch(".size on negative integer"))
1137            } else if size >= 16 {
1138                // If the size is 16 or larger, the i128 value will always fit.
1139                Ok(())
1140            } else {
1141                let mask = (1i128 << (size * 8)) - 1;
1142                if *x & !mask == 0 {
1143                    Ok(())
1144                } else {
1145                    Err(mismatch("uint over .size limit"))
1146                }
1147            }
1148        }
1149        _ => Err(mismatch("uint")),
1150    }
1151}
1152
1153// Check the size of a text string.
1154fn validate_size_tstr(size: u64, value: &Value) -> ValidateResult {
1155    match value {
1156        Value::Text(s) => {
1157            let size: usize = size.try_into().unwrap_or(usize::MAX);
1158            if s.len() > size {
1159                Err(mismatch("tstr over .size limit"))
1160            } else {
1161                Ok(())
1162            }
1163        }
1164        _ => Err(mismatch("tstr")),
1165    }
1166}
1167
1168// Check the size of a byte string.
1169fn validate_size_bstr(size: u64, value: &Value) -> ValidateResult {
1170    match value {
1171        Value::Bytes(b) => {
1172            let size: usize = size.try_into().unwrap_or(usize::MAX);
1173            if b.len() > size {
1174                Err(mismatch("bstr over .size limit"))
1175            } else {
1176                Ok(())
1177            }
1178        }
1179        _ => Err(mismatch("bstr")),
1180    }
1181}
1182
1183fn validate_choiceify_members(choices: &[Node], value: &Value, ctx: &Context) -> ValidateResult {
1184    // Iterate over the input nodes. We expect a list of KeyValue variants.
1185    // For each KeyValue, extract its .value member and try to validate that.
1186    // Because we are in a group context, referring to other groups by name is
1187    // also allowed; we will transparently unwrap those (recursively).
1188    for item in choices {
1189        let validate_result = match item {
1190            Node::KeyValue(kv) => validate(value, &kv.value, ctx),
1191            Node::Rule(rule) => {
1192                // A group may include another group by name. Handling this:
1193                // Dereference the rule. If it leads to a Group, then
1194                // recursively walk the nodes in that group. Otherwise,
1195                // return an error.
1196                validate_choiceify(rule, value, ctx)
1197            }
1198            _ => {
1199                // Reading the CDDL spec, you might expect this case to be
1200                // un-necessary. However, the flatten code always simplifies
1201                // a keyless KeyValue node into just a value. Which means
1202                // that any type might appear here.
1203                validate(value, item, ctx)
1204            }
1205        };
1206
1207        // This part is the same as validate_choice().
1208        // If we matched, return Ok immediately.
1209        // If we didn't, keep searching (unless the error is fatal).
1210        match validate_result {
1211            Ok(()) => {
1212                return Ok(());
1213            }
1214            Err(e) => {
1215                // Only fail if the error is considered fatal.
1216                // Otherwise, we'll keep trying other options.
1217                if e.is_fatal() {
1218                    return Err(e);
1219                }
1220            }
1221        }
1222    }
1223    let expected = format!("choiceified group of {}", choices.len());
1224    Err(mismatch(expected))
1225}
1226
1227/// Validate a "choice-ified group" (the CDDL "&" operator)
1228///
1229/// Each value in the named group will be used as a possible choice.
1230fn validate_choiceify(rule: &Rule, value: &Value, ctx: &Context) -> ValidateResult {
1231    let NodeContext { node, ctx } = ctx.lookup_rule(rule)?;
1232    match node {
1233        Node::Group(g) => validate_choiceify_members(&g.members, value, &ctx),
1234        Node::Rule(r) => validate_choiceify(r, value, &ctx),
1235        _ => Err(ValidateError::Structural(
1236            "improper choiceify target".into(),
1237        )),
1238    }
1239}
1240
1241/// Validate an inline "choice-ified group" (the CDDL "&" operator)
1242///
1243/// Each value in the inline group will be used as a possible choice.
1244fn validate_choiceify_inline(array: &Array, value: &Value, ctx: &Context) -> ValidateResult {
1245    validate_choiceify_members(&array.members, value, ctx)
1246}