biscuit_parser/
builder.rs

1//! helper functions and structure to create tokens and blocks
2use std::{
3    collections::{BTreeMap, BTreeSet, HashMap, HashSet},
4    time::{SystemTime, UNIX_EPOCH},
5};
6
7#[cfg(feature = "datalog-macro")]
8use quote::{quote, ToTokens};
9
10/// Builder for a Datalog value
11#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub enum Term {
13    Variable(String),
14    Integer(i64),
15    Str(String),
16    Date(u64),
17    Bytes(Vec<u8>),
18    Bool(bool),
19    Set(BTreeSet<Term>),
20    Parameter(String),
21    Null,
22    Array(Vec<Term>),
23    Map(BTreeMap<MapKey, Term>),
24}
25
26impl Term {
27    fn extract_parameters(&self, parameters: &mut HashMap<String, Option<Term>>) {
28        match self {
29            Term::Parameter(name) => {
30                parameters.insert(name.to_string(), None);
31            }
32            Term::Set(s) => {
33                for term in s {
34                    term.extract_parameters(parameters);
35                }
36            }
37            Term::Array(a) => {
38                for term in a {
39                    term.extract_parameters(parameters);
40                }
41            }
42            Term::Map(m) => {
43                for (key, term) in m {
44                    if let MapKey::Parameter(name) = key {
45                        parameters.insert(name.to_string(), None);
46                    }
47                    term.extract_parameters(parameters);
48                }
49            }
50            _ => {}
51        }
52    }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
56pub enum MapKey {
57    Parameter(String),
58    Integer(i64),
59    Str(String),
60}
61
62impl From<&Term> for Term {
63    fn from(i: &Term) -> Self {
64        match i {
65            Term::Variable(ref v) => Term::Variable(v.clone()),
66            Term::Integer(ref i) => Term::Integer(*i),
67            Term::Str(ref s) => Term::Str(s.clone()),
68            Term::Date(ref d) => Term::Date(*d),
69            Term::Bytes(ref s) => Term::Bytes(s.clone()),
70            Term::Bool(b) => Term::Bool(*b),
71            Term::Set(ref s) => Term::Set(s.clone()),
72            Term::Parameter(ref p) => Term::Parameter(p.clone()),
73            Term::Null => Term::Null,
74            Term::Array(ref a) => Term::Array(a.clone()),
75            Term::Map(ref m) => Term::Map(m.clone()),
76        }
77    }
78}
79
80impl AsRef<Term> for Term {
81    fn as_ref(&self) -> &Term {
82        self
83    }
84}
85
86#[cfg(feature = "datalog-macro")]
87impl ToTokens for Term {
88    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
89        tokens.extend(match self {
90            Term::Variable(v) => quote! { ::biscuit_auth::builder::Term::Variable(#v.to_string()) },
91            Term::Integer(v) => quote! { ::biscuit_auth::builder::Term::Integer(#v) },
92            Term::Str(v) => quote! { ::biscuit_auth::builder::Term::Str(#v.to_string()) },
93            Term::Date(v) => quote! { ::biscuit_auth::builder::Term::Date(#v) },
94            Term::Bool(v) => quote! { ::biscuit_auth::builder::Term::Bool(#v) },
95            Term::Parameter(v) => quote! { ::biscuit_auth::builder::Term::Parameter(#v.to_string()) },
96            Term::Bytes(v) => quote! { ::biscuit_auth::builder::Term::Bytes(<[u8]>::into_vec(Box::new([ #(#v),*]))) },
97            Term::Set(v) => {
98                quote! {{
99                    use std::iter::FromIterator;
100                    ::biscuit_auth::builder::Term::Set(::std::collections::BTreeSet::from_iter(<[::biscuit_auth::builder::Term]>::into_vec(Box::new([ #(#v),*]))))
101                }}
102            }
103            Term::Null => quote! { ::biscuit_auth::builder::Term::Null },
104            Term::Array(v) => {
105                quote! {{
106                    use std::iter::FromIterator;
107                    ::biscuit_auth::builder::Term::Array(::std::vec::Vec::from_iter(<[::biscuit_auth::builder::Term]>::into_vec( Box::new([ #(#v),*]))))
108                }}
109            }
110            Term::Map(m) => {
111                let  it = m.iter().map(|(key, term)| MapEntry {key, term });
112                quote! {{
113                    use std::iter::FromIterator;
114                    ::biscuit_auth::builder::Term::Map(::std::collections::BTreeMap::from_iter(<[(::biscuit_auth::builder::MapKey,::biscuit_auth::builder::Term)]>::into_vec(Box::new([ #(#it),*]))))
115                }}
116            }
117        })
118    }
119}
120
121#[cfg(feature = "datalog-macro")]
122struct MapEntry<'a> {
123    key: &'a MapKey,
124    term: &'a Term,
125}
126
127#[cfg(feature = "datalog-macro")]
128impl<'a> ToTokens for MapEntry<'a> {
129    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
130        let term = self.term;
131        tokens.extend(match self.key {
132            MapKey::Parameter(p) => {
133                quote! { (::biscuit_auth::builder::MapKey::Parameter(#p.to_string()) , #term )}
134            }
135            MapKey::Integer(i) => {
136                quote! { (::biscuit_auth::builder::MapKey::Integer(#i) , #term )}
137            }
138            MapKey::Str(s) => {
139                quote! { (::biscuit_auth::builder::MapKey::Str(#s.to_string()) , #term )}
140            }
141        });
142    }
143}
144
145#[derive(Clone, Debug, Hash, PartialEq, Eq)]
146pub enum Scope {
147    Authority,
148    Previous,
149    PublicKey(PublicKey),
150    Parameter(String),
151}
152
153#[cfg(feature = "datalog-macro")]
154impl ToTokens for Scope {
155    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
156        tokens.extend(match self {
157            Scope::Authority => quote! { ::biscuit_auth::builder::Scope::Authority},
158            Scope::Previous => quote! { ::biscuit_auth::builder::Scope::Previous},
159            Scope::PublicKey(pk) => {
160                let bytes = pk.key.iter();
161                match pk.algorithm {
162                    Algorithm::Ed25519 => quote! { ::biscuit_auth::builder::Scope::PublicKey(
163                        ::biscuit_auth::PublicKey::from_bytes(&[#(#bytes),*], ::biscuit_auth::builder::Algorithm::Ed25519).unwrap()
164                      )},
165                    Algorithm::Secp256r1 => quote! { ::biscuit_auth::builder::Scope::PublicKey(
166                        ::biscuit_auth::PublicKey::from_bytes(&[#(#bytes),*], ::biscuit_auth::builder::Algorithm::Secp256r1).unwrap()
167                      )},
168                }
169            }
170            Scope::Parameter(v) => {
171                quote! { ::biscuit_auth::builder::Scope::Parameter(#v.to_string())}
172            }
173        })
174    }
175}
176
177/// Builder for a Datalog dicate, used in facts and rules
178#[derive(Debug, Clone, PartialEq, Hash, Eq)]
179pub struct Predicate {
180    pub name: String,
181    pub terms: Vec<Term>,
182}
183
184impl Predicate {
185    pub fn new<T: Into<Vec<Term>>>(name: String, terms: T) -> Predicate {
186        Predicate {
187            name,
188            terms: terms.into(),
189        }
190    }
191}
192
193#[cfg(feature = "datalog-macro")]
194impl ToTokens for Predicate {
195    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
196        let name = &self.name;
197        let terms = self.terms.iter();
198        tokens.extend(quote! {
199            ::biscuit_auth::builder::Predicate::new(
200              #name.to_string(),
201              <[::biscuit_auth::builder::Term]>::into_vec(Box::new([#(#terms),*]))
202            )
203        })
204    }
205}
206
207/// Builder for a Datalog fact
208#[derive(Debug, Clone, PartialEq, Eq)]
209pub struct Fact {
210    pub predicate: Predicate,
211    pub parameters: Option<HashMap<String, Option<Term>>>,
212}
213
214impl Fact {
215    pub fn new<T: Into<Vec<Term>>>(name: String, terms: T) -> Fact {
216        let mut parameters = HashMap::new();
217        let terms: Vec<Term> = terms.into();
218
219        for term in &terms {
220            term.extract_parameters(&mut parameters);
221        }
222        Fact {
223            predicate: Predicate::new(name, terms),
224            parameters: Some(parameters),
225        }
226    }
227}
228
229#[cfg(feature = "datalog-macro")]
230impl ToTokens for Fact {
231    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
232        let name = &self.predicate.name;
233        let terms = self.predicate.terms.iter();
234        tokens.extend(quote! {
235            ::biscuit_auth::builder::Fact::new(
236              #name.to_string(),
237              <[::biscuit_auth::builder::Term]>::into_vec(Box::new([#(#terms),*]))
238            )
239        })
240    }
241}
242
243/// Builder for a Datalog expression
244#[derive(Debug, Clone, PartialEq, Eq)]
245pub struct Expression {
246    pub ops: Vec<Op>,
247}
248
249#[cfg(feature = "datalog-macro")]
250impl ToTokens for Expression {
251    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
252        let ops = self.ops.iter();
253        tokens.extend(quote! {
254          ::biscuit_auth::builder::Expression {
255            ops: <[::biscuit_auth::builder::Op]>::into_vec(Box::new([#(#ops),*]))
256          }
257        });
258    }
259}
260
261/// Builder for an expression operation
262#[derive(Debug, Clone, PartialEq, Eq)]
263pub enum Op {
264    Value(Term),
265    Unary(Unary),
266    Binary(Binary),
267    Closure(Vec<String>, Vec<Op>),
268}
269
270impl Op {
271    fn collect_parameters(&self, parameters: &mut HashMap<String, Option<Term>>) {
272        match self {
273            Op::Value(term) => {
274                term.extract_parameters(parameters);
275            }
276            Op::Closure(_, ops) => {
277                for op in ops {
278                    op.collect_parameters(parameters);
279                }
280            }
281            _ => {}
282        }
283    }
284}
285
286#[derive(Debug, Clone, PartialEq, Eq)]
287pub enum Unary {
288    Negate,
289    Parens,
290    Length,
291    TypeOf,
292    Ffi(String),
293}
294
295#[derive(Debug, Clone, PartialEq, Eq)]
296pub enum Binary {
297    LessThan,
298    GreaterThan,
299    LessOrEqual,
300    GreaterOrEqual,
301    Equal,
302    Contains,
303    Prefix,
304    Suffix,
305    Regex,
306    Add,
307    Sub,
308    Mul,
309    Div,
310    And,
311    Or,
312    Intersection,
313    Union,
314    BitwiseAnd,
315    BitwiseOr,
316    BitwiseXor,
317    NotEqual,
318    HeterogeneousEqual,
319    HeterogeneousNotEqual,
320    LazyAnd,
321    LazyOr,
322    All,
323    Any,
324    Get,
325    Ffi(String),
326    TryOr,
327}
328
329#[cfg(feature = "datalog-macro")]
330impl ToTokens for Op {
331    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
332        tokens.extend(match self {
333            Op::Value(t) => quote! { ::biscuit_auth::builder::Op::Value(#t) },
334            Op::Unary(u) => quote! { ::biscuit_auth::builder::Op::Unary(#u) },
335            Op::Binary(b) => quote! { ::biscuit_auth::builder::Op::Binary(#b) },
336            Op::Closure(params, os) => quote! {
337            ::biscuit_auth::builder::Op::Closure(
338                    <[String]>::into_vec(Box::new([#(#params.to_string()),*])),
339                    <[::biscuit_auth::builder::Op]>::into_vec(Box::new([#(#os),*]))
340                    )
341            },
342        });
343    }
344}
345
346#[cfg(feature = "datalog-macro")]
347impl ToTokens for Unary {
348    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
349        tokens.extend(match self {
350            Unary::Negate => quote! {::biscuit_auth::builder::Unary::Negate },
351            Unary::Parens => quote! {::biscuit_auth::builder::Unary::Parens },
352            Unary::Length => quote! {::biscuit_auth::builder::Unary::Length },
353            Unary::TypeOf => quote! {::biscuit_auth::builder::Unary::TypeOf },
354            Unary::Ffi(name) => quote! {::biscuit_auth::builder::Unary::Ffi(#name.to_string()) },
355        });
356    }
357}
358
359#[cfg(feature = "datalog-macro")]
360impl ToTokens for Binary {
361    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
362        tokens.extend(match self {
363            Binary::LessThan => quote! { ::biscuit_auth::builder::Binary::LessThan  },
364            Binary::GreaterThan => quote! { ::biscuit_auth::builder::Binary::GreaterThan  },
365            Binary::LessOrEqual => quote! { ::biscuit_auth::builder::Binary::LessOrEqual  },
366            Binary::GreaterOrEqual => quote! { ::biscuit_auth::builder::Binary::GreaterOrEqual  },
367            Binary::Equal => quote! { ::biscuit_auth::builder::Binary::Equal  },
368            Binary::Contains => quote! { ::biscuit_auth::builder::Binary::Contains  },
369            Binary::Prefix => quote! { ::biscuit_auth::builder::Binary::Prefix  },
370            Binary::Suffix => quote! { ::biscuit_auth::builder::Binary::Suffix  },
371            Binary::Regex => quote! { ::biscuit_auth::builder::Binary::Regex  },
372            Binary::Add => quote! { ::biscuit_auth::builder::Binary::Add  },
373            Binary::Sub => quote! { ::biscuit_auth::builder::Binary::Sub  },
374            Binary::Mul => quote! { ::biscuit_auth::builder::Binary::Mul  },
375            Binary::Div => quote! { ::biscuit_auth::builder::Binary::Div  },
376            Binary::And => quote! { ::biscuit_auth::builder::Binary::And  },
377            Binary::Or => quote! { ::biscuit_auth::builder::Binary::Or  },
378            Binary::Intersection => quote! { ::biscuit_auth::builder::Binary::Intersection  },
379            Binary::Union => quote! { ::biscuit_auth::builder::Binary::Union  },
380            Binary::BitwiseAnd => quote! { ::biscuit_auth::builder::Binary::BitwiseAnd  },
381            Binary::BitwiseOr => quote! { ::biscuit_auth::builder::Binary::BitwiseOr  },
382            Binary::BitwiseXor => quote! { ::biscuit_auth::builder::Binary::BitwiseXor  },
383            Binary::NotEqual => quote! { ::biscuit_auth::builder::Binary::NotEqual },
384            Binary::HeterogeneousEqual => {
385                quote! { ::biscuit_auth::builder::Binary::HeterogeneousEqual}
386            }
387            Binary::HeterogeneousNotEqual => {
388                quote! { ::biscuit_auth::builder::Binary::HeterogeneousNotEqual}
389            }
390            Binary::LazyAnd => quote! { ::biscuit_auth::builder::Binary::LazyAnd },
391            Binary::LazyOr => quote! { ::biscuit_auth::builder::Binary::LazyOr },
392            Binary::All => quote! { ::biscuit_auth::builder::Binary::All },
393            Binary::Any => quote! { ::biscuit_auth::builder::Binary::Any },
394            Binary::Get => quote! { ::biscuit_auth::builder::Binary::Get },
395            Binary::Ffi(name) => quote! {::biscuit_auth::builder::Binary::Ffi(#name.to_string()) },
396            Binary::TryOr => quote! { ::biscuit_auth::builder::Binary::TryOr },
397        });
398    }
399}
400
401#[derive(Debug, Clone, Hash, PartialEq, Eq)]
402pub struct PublicKey {
403    pub key: Vec<u8>,
404    pub algorithm: Algorithm,
405}
406
407#[derive(Debug, Clone, Hash, PartialEq, Eq)]
408pub enum Algorithm {
409    Ed25519,
410    Secp256r1,
411}
412
413/// Builder for a Datalog rule
414#[derive(Debug, Clone, PartialEq, Eq)]
415pub struct Rule {
416    pub head: Predicate,
417    pub body: Vec<Predicate>,
418    pub expressions: Vec<Expression>,
419    pub parameters: Option<HashMap<String, Option<Term>>>,
420    pub scopes: Vec<Scope>,
421    pub scope_parameters: Option<HashMap<String, Option<PublicKey>>>,
422}
423
424impl Rule {
425    pub fn new(
426        head: Predicate,
427        body: Vec<Predicate>,
428        expressions: Vec<Expression>,
429        scopes: Vec<Scope>,
430    ) -> Rule {
431        let mut parameters = HashMap::new();
432        let mut scope_parameters = HashMap::new();
433
434        for term in &head.terms {
435            term.extract_parameters(&mut parameters);
436        }
437
438        for predicate in &body {
439            for term in &predicate.terms {
440                term.extract_parameters(&mut parameters);
441            }
442        }
443
444        for expression in &expressions {
445            for op in &expression.ops {
446                op.collect_parameters(&mut parameters);
447            }
448        }
449
450        for scope in &scopes {
451            if let Scope::Parameter(name) = &scope {
452                scope_parameters.insert(name.to_string(), None);
453            }
454        }
455
456        Rule {
457            head,
458            body,
459            expressions,
460            parameters: Some(parameters),
461            scopes,
462            scope_parameters: Some(scope_parameters),
463        }
464    }
465
466    pub fn validate_variables(&self) -> Result<(), String> {
467        let mut free_variables: HashSet<String> = HashSet::default();
468        for term in self.head.terms.iter() {
469            if let Term::Variable(s) = term {
470                free_variables.insert(s.to_string());
471            }
472        }
473
474        for e in self.expressions.iter() {
475            for op in e.ops.iter() {
476                if let Op::Value(Term::Variable(s)) = op {
477                    free_variables.insert(s.to_string());
478                }
479            }
480        }
481
482        for predicate in self.body.iter() {
483            for term in predicate.terms.iter() {
484                if let Term::Variable(v) = term {
485                    free_variables.remove(v);
486                    if free_variables.is_empty() {
487                        return Ok(());
488                    }
489                }
490            }
491        }
492
493        if free_variables.is_empty() {
494            Ok(())
495        } else {
496            Err(format!(
497                    "the rule contains variables that are not bound by predicates in the rule's body: {}",
498                    free_variables
499                    .iter()
500                    .map(|s| format!("${}", s))
501                    .collect::<Vec<_>>()
502                    .join(", ")
503                    ))
504        }
505    }
506}
507
508#[cfg(feature = "datalog-macro")]
509impl ToTokens for Rule {
510    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
511        let head = &self.head;
512        let body = self.body.iter();
513        let expressions = self.expressions.iter();
514        let scopes = self.scopes.iter();
515        tokens.extend(quote! {
516          ::biscuit_auth::builder::Rule::new(
517            #head,
518            <[::biscuit_auth::builder::Predicate]>::into_vec(Box::new([#(#body),*])),
519            <[::biscuit_auth::builder::Expression]>::into_vec(Box::new([#(#expressions),*])),
520            <[::biscuit_auth::builder::Scope]>::into_vec(Box::new([#(#scopes),*]))
521          )
522        });
523    }
524}
525
526/// Builder for a Biscuit check
527#[derive(Debug, Clone, PartialEq, Eq)]
528pub struct Check {
529    pub queries: Vec<Rule>,
530    pub kind: CheckKind,
531}
532
533#[derive(Debug, Clone, PartialEq, Eq)]
534pub enum CheckKind {
535    One,
536    All,
537    Reject,
538}
539
540#[cfg(feature = "datalog-macro")]
541impl ToTokens for Check {
542    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
543        let queries = self.queries.iter();
544        let kind = &self.kind;
545        tokens.extend(quote! {
546          ::biscuit_auth::builder::Check {
547            queries: <[::biscuit_auth::builder::Rule]>::into_vec(Box::new([#(#queries),*])),
548            kind: #kind,
549          }
550        });
551    }
552}
553
554#[cfg(feature = "datalog-macro")]
555impl ToTokens for CheckKind {
556    fn to_tokens(&self, tokens: &mut quote::__private::TokenStream) {
557        tokens.extend(match self {
558            CheckKind::One => quote! {
559              ::biscuit_auth::builder::CheckKind::One
560            },
561            CheckKind::All => quote! {
562              ::biscuit_auth::builder::CheckKind::All
563            },
564            CheckKind::Reject => quote! {
565              ::biscuit_auth::builder::CheckKind::Reject
566            },
567        });
568    }
569}
570
571#[derive(Debug, Clone, PartialEq, Eq)]
572pub enum PolicyKind {
573    Allow,
574    Deny,
575}
576
577#[cfg(feature = "datalog-macro")]
578impl ToTokens for PolicyKind {
579    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
580        tokens.extend(match self {
581            PolicyKind::Allow => quote! {
582              ::biscuit_auth::builder::PolicyKind::Allow
583            },
584            PolicyKind::Deny => quote! {
585              ::biscuit_auth::builder::PolicyKind::Deny
586            },
587        });
588    }
589}
590
591/// Builder for a Biscuit policy
592#[derive(Debug, Clone, PartialEq, Eq)]
593pub struct Policy {
594    pub queries: Vec<Rule>,
595    pub kind: PolicyKind,
596}
597
598#[cfg(feature = "datalog-macro")]
599impl ToTokens for Policy {
600    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
601        let queries = self.queries.iter();
602        let kind = &self.kind;
603        tokens.extend(quote! {
604          ::biscuit_auth::builder::Policy{
605            kind: #kind,
606            queries: <[::biscuit_auth::builder::Rule]>::into_vec(Box::new([#(#queries),*])),
607          }
608        });
609    }
610}
611
612/// creates a new fact
613pub fn fact<I: AsRef<Term>>(name: &str, terms: &[I]) -> Fact {
614    let pred = pred(name, terms);
615    Fact::new(pred.name, pred.terms)
616}
617
618/// creates a predicate
619pub fn pred<I: AsRef<Term>>(name: &str, terms: &[I]) -> Predicate {
620    Predicate {
621        name: name.to_string(),
622        terms: terms.iter().map(|term| term.as_ref().clone()).collect(),
623    }
624}
625
626/// creates a rule
627pub fn rule<T: AsRef<Term>>(head_name: &str, head_terms: &[T], predicates: &[Predicate]) -> Rule {
628    Rule::new(
629        pred(head_name, head_terms),
630        predicates.to_vec(),
631        Vec::new(),
632        vec![],
633    )
634}
635
636/// creates a rule with constraints
637pub fn constrained_rule<T: AsRef<Term>>(
638    head_name: &str,
639    head_terms: &[T],
640    predicates: &[Predicate],
641    expressions: &[Expression],
642) -> Rule {
643    Rule::new(
644        pred(head_name, head_terms),
645        predicates.to_vec(),
646        expressions.to_vec(),
647        vec![],
648    )
649}
650
651/// creates a check
652pub fn check<P: AsRef<Predicate>>(predicates: &[P], kind: CheckKind) -> Check {
653    let empty_terms: &[Term] = &[];
654    Check {
655        queries: vec![Rule::new(
656            pred("query", empty_terms),
657            predicates.iter().map(|p| p.as_ref().clone()).collect(),
658            vec![],
659            vec![],
660        )],
661        kind,
662    }
663}
664
665/// creates an integer value
666pub fn int(i: i64) -> Term {
667    Term::Integer(i)
668}
669
670/// creates a string
671pub fn string(s: &str) -> Term {
672    Term::Str(s.to_string())
673}
674
675/// creates a date
676///
677/// internally the date will be stored as seconds since UNIX_EPOCH
678pub fn date(t: &SystemTime) -> Term {
679    let dur = t.duration_since(UNIX_EPOCH).unwrap();
680    Term::Date(dur.as_secs())
681}
682
683/// creates a variable for a rule
684pub fn var(s: &str) -> Term {
685    Term::Variable(s.to_string())
686}
687
688/// creates a variable for a rule
689pub fn variable(s: &str) -> Term {
690    Term::Variable(s.to_string())
691}
692
693/// creates a byte array
694pub fn bytes(s: &[u8]) -> Term {
695    Term::Bytes(s.to_vec())
696}
697
698/// creates a boolean
699pub fn boolean(b: bool) -> Term {
700    Term::Bool(b)
701}
702
703/// creates a set
704pub fn set(s: BTreeSet<Term>) -> Term {
705    Term::Set(s)
706}
707
708/// creates a null
709pub fn null() -> Term {
710    Term::Null
711}
712
713/// creates an array
714pub fn array(a: Vec<Term>) -> Term {
715    Term::Array(a)
716}
717
718/// creates a map
719pub fn map(m: BTreeMap<MapKey, Term>) -> Term {
720    Term::Map(m)
721}
722
723/// creates a parameter
724pub fn parameter(p: &str) -> Term {
725    Term::Parameter(p.to_string())
726}