cedar_policy_core/ast/
value.rs

1/*
2 * Copyright Cedar Contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use crate::ast::*;
18use crate::parser::Loc;
19use std::collections::{BTreeMap, BTreeSet, HashSet};
20use std::sync::Arc;
21
22use itertools::Itertools;
23use miette::Diagnostic;
24use serde::{Deserialize, Serialize};
25use smol_str::SmolStr;
26use thiserror::Error;
27
28/// This describes all the values which could be the dynamic result of evaluating an `Expr`.
29/// Cloning is O(1).
30#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(into = "Expr")]
32#[serde(try_from = "Expr")]
33pub struct Value {
34    /// Underlying actual value
35    pub value: ValueKind,
36    /// Source location associated with the value, if any
37    pub loc: Option<Loc>,
38}
39
40/// This describes all the values which could be the dynamic result of evaluating an `Expr`.
41/// Cloning is O(1).
42#[derive(Debug, Clone, PartialOrd, Ord, Serialize, Deserialize)]
43#[serde(into = "Expr")]
44#[serde(try_from = "Expr")]
45pub enum ValueKind {
46    /// anything that is a Literal can also be the dynamic result of evaluating an `Expr`
47    Lit(Literal),
48    /// Evaluating an `Expr` can result in a first-class set
49    Set(Set),
50    /// Evaluating an `Expr` can result in a first-class anonymous record (keyed on String)
51    Record(Arc<BTreeMap<SmolStr, Value>>),
52    /// Evaluating an `Expr` can result in an extension value
53    ExtensionValue(Arc<ExtensionValueWithArgs>),
54}
55
56// Custom impl of `Ord`, ignoring the `Loc`s
57impl Ord for Value {
58    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
59        self.value.cmp(&other.value)
60    }
61}
62
63impl PartialOrd<Value> for Value {
64    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
65        // delegate to `Ord`
66        Some(self.cmp(other))
67    }
68}
69
70impl Value {
71    /// Create a new empty set
72    pub fn empty_set(loc: Option<Loc>) -> Self {
73        Self {
74            value: ValueKind::empty_set(),
75            loc,
76        }
77    }
78
79    /// Create a new empty record
80    pub fn empty_record(loc: Option<Loc>) -> Self {
81        Self {
82            value: ValueKind::empty_record(),
83            loc,
84        }
85    }
86
87    /// Create a `Value` from anything that implements `Into<ValueKind>` and an
88    /// optional source location
89    pub fn new(value: impl Into<ValueKind>, loc: Option<Loc>) -> Self {
90        Self {
91            value: value.into(),
92            loc,
93        }
94    }
95
96    /// Create a set with the given `Value`s as elements
97    pub fn set(vals: impl IntoIterator<Item = Value>, loc: Option<Loc>) -> Self {
98        Self {
99            value: ValueKind::set(vals),
100            loc,
101        }
102    }
103
104    /// Create a set with the given `Literal`s as elements
105    ///
106    /// the resulting `Value` will have the given `loc` attached, but its
107    /// individual `Literal` elements will not have a source loc attached
108    pub fn set_of_lits(lits: impl IntoIterator<Item = Literal>, loc: Option<Loc>) -> Self {
109        Self {
110            value: ValueKind::set_of_lits(lits),
111            loc,
112        }
113    }
114
115    /// Create a record with the given (key, value) pairs
116    pub fn record<K: Into<SmolStr>, V: Into<Value>>(
117        pairs: impl IntoIterator<Item = (K, V)>,
118        loc: Option<Loc>,
119    ) -> Self {
120        Self {
121            value: ValueKind::record(pairs),
122            loc,
123        }
124    }
125
126    /// Create a record with the given attributes/value mapping.
127    pub fn record_arc(pairs: Arc<BTreeMap<SmolStr, Value>>, loc: Option<Loc>) -> Self {
128        Self {
129            value: ValueKind::record_arc(pairs),
130            loc,
131        }
132    }
133
134    /// Return the `Value`, but with the given `Loc` (or `None`)
135    pub fn with_maybe_source_loc(self, loc: Option<Loc>) -> Self {
136        Self { loc, ..self }
137    }
138
139    /// Get the `ValueKind` for this `Value`
140    pub fn value_kind(&self) -> &ValueKind {
141        &self.value
142    }
143
144    /// Get the `Loc` attached to this `Value`, if there is one
145    pub fn source_loc(&self) -> Option<&Loc> {
146        self.loc.as_ref()
147    }
148
149    /// If the value is a `Literal`, get a reference to the underlying `Literal`
150    pub(crate) fn try_as_lit(&self) -> Option<&Literal> {
151        self.value.try_as_lit()
152    }
153
154    /// The `PartialEq` and `Eq` implementations for `Value` ignore the source location.
155    /// If you actually want to check that two values are equal _and_ have the
156    /// same source location, you can use this.
157    pub fn eq_and_same_source_loc(&self, other: &Self) -> bool {
158        self == other && self.source_loc() == other.source_loc()
159    }
160}
161
162impl ValueKind {
163    /// Create a new empty set
164    pub fn empty_set() -> Self {
165        Self::Set(Set::empty())
166    }
167
168    /// Create a new empty record
169    pub fn empty_record() -> Self {
170        Self::Record(Arc::new(BTreeMap::new()))
171    }
172
173    /// Create a set with the given `Value`s as elements
174    pub fn set(vals: impl IntoIterator<Item = Value>) -> Self {
175        Self::Set(Set::new(vals))
176    }
177
178    /// Create a set with the given `Literal`s as elements
179    pub fn set_of_lits(lits: impl IntoIterator<Item = Literal>) -> Self {
180        Self::Set(Set::from_lits(lits))
181    }
182
183    /// Create a record with the given (key, value) pairs
184    pub fn record<K: Into<SmolStr>, V: Into<Value>>(
185        pairs: impl IntoIterator<Item = (K, V)>,
186    ) -> Self {
187        Self::Record(Arc::new(
188            pairs
189                .into_iter()
190                .map(|(k, v)| (k.into(), v.into()))
191                .collect(),
192        ))
193    }
194
195    /// Create a record with the given attributes/value mapping.
196    pub fn record_arc(pairs: Arc<BTreeMap<SmolStr, Value>>) -> Self {
197        Self::Record(pairs)
198    }
199
200    /// If the value is a `Literal`, get a reference to the underlying `Literal`
201    pub(crate) fn try_as_lit(&self) -> Option<&Literal> {
202        match &self {
203            Self::Lit(lit) => Some(lit),
204            _ => None,
205        }
206    }
207}
208
209#[derive(Debug, Error)]
210/// An error that can be thrown converting an expression to a value
211pub enum NotValue {
212    /// General error for non-values
213    #[error("not a value")]
214    NotValue {
215        /// Source location info for the expr that wasn't a value
216        loc: Option<Loc>,
217    },
218}
219
220impl Diagnostic for NotValue {
221    fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
222        match self {
223            Self::NotValue { loc } => loc.as_ref().map(|loc| {
224                Box::new(std::iter::once(miette::LabeledSpan::underline(loc.span)))
225                    as Box<dyn Iterator<Item = _>>
226            }),
227        }
228    }
229
230    fn source_code(&self) -> Option<&dyn miette::SourceCode> {
231        match self {
232            Self::NotValue { loc } => loc.as_ref().map(|loc| &loc.src as &dyn miette::SourceCode),
233        }
234    }
235}
236
237impl TryFrom<Expr> for Value {
238    type Error = NotValue;
239
240    fn try_from(expr: Expr) -> Result<Self, Self::Error> {
241        let loc = expr.source_loc().cloned();
242        Ok(Self {
243            value: ValueKind::try_from(expr)?,
244            loc,
245        })
246    }
247}
248
249impl TryFrom<Expr> for ValueKind {
250    type Error = NotValue;
251
252    fn try_from(expr: Expr) -> Result<Self, Self::Error> {
253        let loc = expr.source_loc().cloned();
254        match expr.into_expr_kind() {
255            ExprKind::Lit(lit) => Ok(Self::Lit(lit)),
256            ExprKind::Unknown(_) => Err(NotValue::NotValue { loc }),
257            ExprKind::Var(_) => Err(NotValue::NotValue { loc }),
258            ExprKind::Slot(_) => Err(NotValue::NotValue { loc }),
259            ExprKind::If { .. } => Err(NotValue::NotValue { loc }),
260            ExprKind::And { .. } => Err(NotValue::NotValue { loc }),
261            ExprKind::Or { .. } => Err(NotValue::NotValue { loc }),
262            ExprKind::UnaryApp { .. } => Err(NotValue::NotValue { loc }),
263            ExprKind::BinaryApp { .. } => Err(NotValue::NotValue { loc }),
264            ExprKind::ExtensionFunctionApp { .. } => Err(NotValue::NotValue { loc }),
265            ExprKind::GetAttr { .. } => Err(NotValue::NotValue { loc }),
266            ExprKind::HasAttr { .. } => Err(NotValue::NotValue { loc }),
267            ExprKind::Like { .. } => Err(NotValue::NotValue { loc }),
268            ExprKind::Is { .. } => Err(NotValue::NotValue { loc }),
269            ExprKind::Set(members) => members
270                .iter()
271                .map(|e| Value::try_from(e.clone()))
272                .collect::<Result<Set, _>>()
273                .map(Self::Set),
274            ExprKind::Record(map) => map
275                .iter()
276                .map(|(k, v)| Value::try_from(v.clone()).map(|v| (k.clone(), v)))
277                .collect::<Result<BTreeMap<SmolStr, Value>, _>>()
278                .map(|m| Self::Record(Arc::new(m))),
279        }
280    }
281}
282
283/// `Value`'s internal representation of a `Set`
284#[derive(Debug, Clone)]
285pub struct Set {
286    /// the values in the set, stored in a `BTreeSet`
287    pub authoritative: Arc<BTreeSet<Value>>,
288    /// if possible, `HashSet<Literal>` representation of the set.
289    /// (This is possible if all the elements are literals.)
290    /// Some operations are much faster in this case.
291    ///
292    /// INVARIANT (FastRepr)
293    /// we guarantee that if the elements are all
294    /// literals, then this will be `Some`. (This allows us to further
295    /// optimize e.g. equality checks between sets: for instance, we know
296    /// that if one set has `fast` and another does not, the sets can't be
297    /// equal.)
298    pub fast: Option<Arc<HashSet<Literal>>>,
299}
300
301impl Set {
302    /// Create an empty set
303    pub fn empty() -> Self {
304        Self {
305            authoritative: Arc::new(BTreeSet::new()),
306            fast: Some(Arc::new(HashSet::new())),
307        }
308    }
309
310    /// Create a set with the given `Value`s as elements
311    pub fn new(vals: impl IntoIterator<Item = Value>) -> Self {
312        let authoritative: BTreeSet<Value> = vals.into_iter().collect();
313        let fast: Option<Arc<HashSet<Literal>>> = authoritative
314            .iter()
315            .map(|v| v.try_as_lit().cloned())
316            .collect::<Option<HashSet<Literal>>>()
317            .map(Arc::new);
318        Self {
319            authoritative: Arc::new(authoritative),
320            fast,
321        }
322    }
323
324    /// Create a set with the given `Literal`s as elements
325    pub fn from_lits(lits: impl IntoIterator<Item = Literal>) -> Self {
326        let fast: HashSet<Literal> = lits.into_iter().collect();
327        let authoritative: BTreeSet<Value> = fast
328            .iter()
329            .map(|lit| Value {
330                value: ValueKind::Lit(lit.clone()),
331                loc: None,
332            })
333            .collect();
334        Self {
335            authoritative: Arc::new(authoritative),
336            fast: Some(Arc::new(fast)),
337        }
338    }
339
340    /// Get the number of items in the set
341    pub fn len(&self) -> usize {
342        self.authoritative.len()
343    }
344
345    /// Convenience method to check if a set is empty
346    pub fn is_empty(&self) -> bool {
347        self.len() == 0
348    }
349
350    /// Borrowed iterator
351    pub fn iter(&self) -> impl Iterator<Item = &Value> {
352        self.authoritative.iter()
353    }
354}
355
356impl FromIterator<Value> for Set {
357    fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
358        let (literals, non_literals): (BTreeSet<_>, BTreeSet<_>) = iter
359            .into_iter()
360            .partition(|v| matches!(&v.value, ValueKind::Lit { .. }));
361
362        if non_literals.is_empty() {
363            Self::from_iter(literals.into_iter().map(|v| match v {
364                Value {
365                    value: ValueKind::Lit(lit),
366                    ..
367                } => lit,
368                // PANIC SAFETY: This is unreachable as every item in `literals` matches ValueKind::Lit
369                #[allow(clippy::unreachable)]
370                _ => unreachable!(),
371            }))
372        } else {
373            // INVARIANT (FastRepr)
374            // There are non-literals, so we need `fast` should be `None`
375            // We also need to add all the literals back into the set
376            let mut all_items = non_literals;
377            let mut literals = literals;
378            all_items.append(&mut literals);
379            Self {
380                authoritative: Arc::new(all_items),
381                fast: None,
382            }
383        }
384    }
385}
386
387impl FromIterator<Literal> for Set {
388    fn from_iter<T: IntoIterator<Item = Literal>>(iter: T) -> Self {
389        // INVARIANT (FastRepr)
390        // There are 0 non-literals, so we need to populate `fast`
391        let fast: HashSet<Literal> = iter.into_iter().collect();
392        Self {
393            authoritative: Arc::new(fast.iter().cloned().map(Into::into).collect()),
394            fast: Some(Arc::new(fast)),
395        }
396    }
397}
398
399// Trying to derive `PartialEq` for `ValueKind` fails with a compile error (at
400// least, as of this writing) due to the `Arc<dyn>`, so we write out the
401// implementation manually.
402impl PartialEq for ValueKind {
403    fn eq(&self, other: &Self) -> bool {
404        match (self, other) {
405            (ValueKind::Lit(lit1), ValueKind::Lit(lit2)) => lit1 == lit2,
406            (ValueKind::Set(set1), ValueKind::Set(set2)) => set1 == set2,
407            (ValueKind::Record(r1), ValueKind::Record(r2)) => r1 == r2,
408            (ValueKind::ExtensionValue(ev1), ValueKind::ExtensionValue(ev2)) => ev1 == ev2,
409            (_, _) => false, // values of different types are not equal
410        }
411    }
412}
413
414impl Eq for ValueKind {}
415
416// The implementation of `PartialEq` for `Value` ignores the `Loc` of the values.
417impl PartialEq for Value {
418    fn eq(&self, other: &Value) -> bool {
419        self.value == other.value
420    }
421}
422
423impl Eq for Value {}
424
425// PartialEq on Set is optimized to take advantage of the internal invariant documented on `Set`
426impl PartialEq for Set {
427    fn eq(&self, other: &Self) -> bool {
428        match (self.fast.as_ref(), other.fast.as_ref()) {
429            (Some(rc1), Some(rc2)) => rc1 == rc2,
430            (Some(_), None) => false, // due to internal invariant documented on `Set`, we know that one set contains a non-literal and the other does not
431            (None, Some(_)) => false, // due to internal invariant documented on `Set`, we know that one set contains a non-literal and the other does not
432            (None, None) => self.authoritative.as_ref() == other.authoritative.as_ref(),
433        }
434    }
435}
436
437impl Eq for Set {}
438
439// Ord on Set compares only the `authoritative` version; note that HashSet
440// doesn't implement Ord
441impl Ord for Set {
442    fn cmp(&self, other: &Set) -> std::cmp::Ordering {
443        self.authoritative
444            .as_ref()
445            .cmp(other.authoritative.as_ref())
446    }
447}
448
449impl PartialOrd<Set> for Set {
450    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
451        // delegate to `Ord`
452        Some(self.cmp(other))
453    }
454}
455
456impl StaticallyTyped for Value {
457    fn type_of(&self) -> Type {
458        self.value.type_of()
459    }
460}
461
462impl StaticallyTyped for ValueKind {
463    fn type_of(&self) -> Type {
464        match self {
465            Self::Lit(lit) => lit.type_of(),
466            Self::Set(_) => Type::Set,
467            Self::Record(_) => Type::Record,
468            Self::ExtensionValue(ev) => ev.type_of(),
469        }
470    }
471}
472
473impl std::fmt::Display for Value {
474    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
475        write!(f, "{}", self.value)
476    }
477}
478
479impl std::fmt::Display for ValueKind {
480    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
481        match self {
482            Self::Lit(lit) => write!(f, "{}", lit),
483            Self::Set(Set {
484                fast,
485                authoritative,
486            }) => {
487                match authoritative.len() {
488                    0 => write!(f, "[]"),
489                    n @ 1..=5 => {
490                        write!(f, "[")?;
491                        if let Some(rc) = fast {
492                            // sort the elements, because we want the Display output to be
493                            // deterministic, particularly for tests which check equality
494                            // of error messages
495                            for (i, item) in rc.as_ref().iter().sorted_unstable().enumerate() {
496                                write!(f, "{item}")?;
497                                if i < n - 1 {
498                                    write!(f, ", ")?;
499                                }
500                            }
501                        } else {
502                            // don't need to sort the elements in this case because BTreeSet iterates
503                            // in a deterministic order already
504                            for (i, item) in authoritative.as_ref().iter().enumerate() {
505                                write!(f, "{item}")?;
506                                if i < n - 1 {
507                                    write!(f, ", ")?;
508                                }
509                            }
510                        }
511                        write!(f, "]")?;
512                        Ok(())
513                    }
514                    n => write!(f, "<set with {} elements>", n),
515                }
516            }
517            Self::Record(record) => {
518                write!(f, "<first-class record with {} fields>", record.len())
519            }
520            Self::ExtensionValue(ev) => write!(f, "{}", ev),
521        }
522    }
523}
524
525/// Create a `Value` directly from a `Vec<Value>`, or `Vec<T> where T: Into<Value>`
526/// (so `Vec<Integer>`, `Vec<String>`, etc)
527///
528/// This impl does not propagate source location; the resulting `Value` will
529/// have no source location info attached
530impl<T: Into<Value>> From<Vec<T>> for Value {
531    fn from(v: Vec<T>) -> Self {
532        Self::set(v.into_iter().map(Into::into), None)
533    }
534}
535
536/// Create a `ValueKind` directly from a `Vec<Value>`, or `Vec<T> where T: Into<Value>`
537/// (so `Vec<Integer>`, `Vec<String>`, etc)
538impl<T: Into<Value>> From<Vec<T>> for ValueKind {
539    fn from(v: Vec<T>) -> Self {
540        Self::set(v.into_iter().map(Into::into))
541    }
542}
543
544/// Create a `Value` directly from a `Literal`, or from anything that implements
545/// `Into<Literal>` (so `Integer`, `&str`, `EntityUID`, etc)
546///
547/// This impl does not propagate source location; the resulting `Value` will
548/// have no source location info attached
549impl<T: Into<Literal>> From<T> for Value {
550    fn from(lit: T) -> Self {
551        Self {
552            value: lit.into().into(),
553            loc: None,
554        }
555    }
556}
557
558/// Create a `ValueKind` directly from a `Literal`, or from anything that implements
559/// `Into<Literal>` (so `Integer`, `&str`, `EntityUID`, etc)
560impl<T: Into<Literal>> From<T> for ValueKind {
561    fn from(lit: T) -> Self {
562        Self::Lit(lit.into())
563    }
564}
565
566// PANIC SAFETY: Unit Test Code
567#[allow(clippy::panic)]
568#[cfg(test)]
569mod test {
570    use super::*;
571
572    #[test]
573    fn values() {
574        assert_eq!(
575            Value::from(true),
576            Value {
577                value: ValueKind::Lit(Literal::Bool(true)),
578                loc: None,
579            },
580        );
581        assert_eq!(
582            Value::from(false),
583            Value {
584                value: ValueKind::Lit(Literal::Bool(false)),
585                loc: None,
586            },
587        );
588        assert_eq!(
589            Value::from(23),
590            Value {
591                value: ValueKind::Lit(Literal::Long(23)),
592                loc: None,
593            },
594        );
595        assert_eq!(
596            Value::from(-47),
597            Value {
598                value: ValueKind::Lit(Literal::Long(-47)),
599                loc: None,
600            },
601        );
602        assert_eq!(
603            Value::from("hello"),
604            Value {
605                value: ValueKind::Lit(Literal::String("hello".into())),
606                loc: None,
607            },
608        );
609        assert_eq!(
610            Value::from("hello".to_owned()),
611            Value {
612                value: ValueKind::Lit(Literal::String("hello".into())),
613                loc: None,
614            },
615        );
616        assert_eq!(
617            Value::from(String::new()),
618            Value {
619                value: ValueKind::Lit(Literal::String(SmolStr::default())),
620                loc: None,
621            },
622        );
623        assert_eq!(
624            Value::from(""),
625            Value {
626                value: ValueKind::Lit(Literal::String(SmolStr::default())),
627                loc: None,
628            },
629        );
630        assert_eq!(
631            Value::from(vec![2, -3, 40]),
632            Value::set(vec![Value::from(2), Value::from(-3), Value::from(40)], None),
633        );
634        assert_eq!(
635            Value::from(vec![Literal::from(false), Literal::from("eggs")]),
636            Value::set(vec![Value::from(false), Value::from("eggs")], None),
637        );
638        assert_eq!(
639            Value::set(vec![Value::from(false), Value::from("eggs")], None),
640            Value::set_of_lits(vec![Literal::from(false), Literal::from("eggs")], None),
641        );
642
643        let mut rec1: BTreeMap<SmolStr, Value> = BTreeMap::new();
644        rec1.insert("ham".into(), 3.into());
645        rec1.insert("eggs".into(), "hickory".into());
646        assert_eq!(
647            Value::record(rec1.clone(), None),
648            Value {
649                value: ValueKind::Record(Arc::new(rec1)),
650                loc: None,
651            },
652        );
653
654        let mut rec2: BTreeMap<SmolStr, Value> = BTreeMap::new();
655        rec2.insert("hi".into(), "ham".into());
656        rec2.insert("eggs".into(), "hickory".into());
657        assert_eq!(
658            Value::record(vec![("hi", "ham"), ("eggs", "hickory"),], None),
659            Value {
660                value: ValueKind::Record(Arc::new(rec2)),
661                loc: None,
662            },
663        );
664
665        assert_eq!(
666            Value::from(EntityUID::with_eid("foo")),
667            Value {
668                value: ValueKind::Lit(Literal::EntityUID(Arc::new(EntityUID::with_eid("foo")))),
669                loc: None,
670            },
671        );
672    }
673
674    #[test]
675    fn value_types() {
676        assert_eq!(Value::from(false).type_of(), Type::Bool);
677        assert_eq!(Value::from(23).type_of(), Type::Long);
678        assert_eq!(Value::from(-47).type_of(), Type::Long);
679        assert_eq!(Value::from("hello").type_of(), Type::String);
680        assert_eq!(Value::from(vec![2, -3, 40]).type_of(), Type::Set);
681        assert_eq!(Value::empty_set(None).type_of(), Type::Set);
682        assert_eq!(Value::empty_record(None).type_of(), Type::Record);
683        assert_eq!(
684            Value::record(vec![("hello", Value::from("ham"))], None).type_of(),
685            Type::Record
686        );
687        assert_eq!(
688            Value::from(EntityUID::with_eid("foo")).type_of(),
689            Type::entity_type(
690                Name::parse_unqualified_name("test_entity_type").expect("valid identifier")
691            )
692        );
693    }
694
695    #[test]
696    fn test_set_is_empty_for_empty_set() {
697        let set = Set {
698            authoritative: Arc::new(BTreeSet::new()),
699            fast: Some(Arc::new(HashSet::new())),
700        };
701        assert!(set.is_empty());
702    }
703
704    #[test]
705    fn test_set_is_not_empty_for_set_with_values() {
706        let set = Set {
707            authoritative: Arc::new(BTreeSet::from([Value::from("abc")])),
708            fast: None,
709        };
710        assert!(!set.is_empty());
711    }
712
713    #[test]
714    fn pretty_printer() {
715        assert_eq!(Value::from("abc").to_string(), r#""abc""#);
716        assert_eq!(Value::from("\t").to_string(), r#""\t""#);
717        assert_eq!(Value::from("🐈").to_string(), r#""🐈""#);
718    }
719
720    #[test]
721    fn set_collect() {
722        let v = vec![Value {
723            value: 1.into(),
724            loc: None,
725        }];
726        let set: Set = v.into_iter().collect();
727        assert_eq!(set.len(), 1);
728        let v2 = vec![Value {
729            value: ValueKind::Set(set),
730            loc: None,
731        }];
732        let set2: Set = v2.into_iter().collect();
733        assert_eq!(set2.len(), 1);
734    }
735}