biscuit_auth/token/builder/
fact.rs1use std::{collections::HashMap, convert::TryFrom, fmt, str::FromStr};
6
7use nom::Finish;
8
9use crate::{
10 datalog::{self, SymbolTable},
11 error,
12};
13
14use super::{Convert, Predicate, Term, ToAnyParam};
15
16#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct Fact {
19 pub predicate: Predicate,
20 pub parameters: Option<HashMap<String, Option<Term>>>,
21}
22
23impl Fact {
24 pub fn new<T: Into<Vec<Term>>>(name: String, terms: T) -> Fact {
25 let mut parameters = HashMap::new();
26 let terms: Vec<Term> = terms.into();
27
28 for term in &terms {
29 term.extract_parameters(&mut parameters);
30 }
31 Fact {
32 predicate: Predicate::new(name, terms),
33 parameters: Some(parameters),
34 }
35 }
36
37 pub fn validate(&self) -> Result<(), error::Token> {
38 match &self.parameters {
39 None => Ok(()),
40 Some(parameters) => {
41 let invalid_parameters = parameters
42 .iter()
43 .filter_map(
44 |(name, opt_term)| {
45 if opt_term.is_none() {
46 Some(name)
47 } else {
48 None
49 }
50 },
51 )
52 .map(|name| name.to_string())
53 .collect::<Vec<_>>();
54
55 if invalid_parameters.is_empty() {
56 Ok(())
57 } else {
58 Err(error::Token::Language(
59 biscuit_parser::error::LanguageError::Parameters {
60 missing_parameters: invalid_parameters,
61 unused_parameters: vec![],
62 },
63 ))
64 }
65 }
66 }
67 }
68
69 pub fn set<T: Into<Term>>(&mut self, name: &str, term: T) -> Result<(), error::Token> {
71 if let Some(parameters) = self.parameters.as_mut() {
72 match parameters.get_mut(name) {
73 None => Err(error::Token::Language(
74 biscuit_parser::error::LanguageError::Parameters {
75 missing_parameters: vec![],
76 unused_parameters: vec![name.to_string()],
77 },
78 )),
79 Some(v) => {
80 *v = Some(term.into());
81 Ok(())
82 }
83 }
84 } else {
85 Err(error::Token::Language(
86 biscuit_parser::error::LanguageError::Parameters {
87 missing_parameters: vec![],
88 unused_parameters: vec![name.to_string()],
89 },
90 ))
91 }
92 }
93
94 pub fn set_lenient<T: Into<Term>>(&mut self, name: &str, term: T) -> Result<(), error::Token> {
97 if let Some(parameters) = self.parameters.as_mut() {
98 match parameters.get_mut(name) {
99 None => Ok(()),
100 Some(v) => {
101 *v = Some(term.into());
102 Ok(())
103 }
104 }
105 } else {
106 Err(error::Token::Language(
107 biscuit_parser::error::LanguageError::Parameters {
108 missing_parameters: vec![],
109 unused_parameters: vec![name.to_string()],
110 },
111 ))
112 }
113 }
114
115 #[cfg(feature = "datalog-macro")]
116 pub fn set_macro_param<T: ToAnyParam>(
117 &mut self,
118 name: &str,
119 param: T,
120 ) -> Result<(), error::Token> {
121 use super::AnyParam;
122
123 match param.to_any_param() {
124 AnyParam::Term(t) => self.set_lenient(name, t),
125 AnyParam::PublicKey(_) => Ok(()),
126 }
127 }
128
129 pub(super) fn apply_parameters(&mut self) {
130 if let Some(parameters) = self.parameters.clone() {
131 self.predicate.terms = self
132 .predicate
133 .terms
134 .drain(..)
135 .map(|t| t.apply_parameters(¶meters))
136 .collect();
137 }
138 }
139}
140
141impl Convert<datalog::Fact> for Fact {
142 fn convert(&self, symbols: &mut SymbolTable) -> datalog::Fact {
143 let mut fact = self.clone();
144 fact.apply_parameters();
145
146 datalog::Fact {
147 predicate: fact.predicate.convert(symbols),
148 }
149 }
150
151 fn convert_from(f: &datalog::Fact, symbols: &SymbolTable) -> Result<Self, error::Format> {
152 Ok(Fact {
153 predicate: Predicate::convert_from(&f.predicate, symbols)?,
154 parameters: None,
155 })
156 }
157}
158
159impl fmt::Display for Fact {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 let mut fact = self.clone();
162 fact.apply_parameters();
163
164 fact.predicate.fmt(f)
165 }
166}
167
168impl From<biscuit_parser::builder::Fact> for Fact {
169 fn from(f: biscuit_parser::builder::Fact) -> Self {
170 Fact {
171 predicate: f.predicate.into(),
172 parameters: f.parameters.map(|h| {
174 h.into_iter()
175 .map(|(k, v)| (k, v.map(|term| term.into())))
176 .collect()
177 }),
178 }
179 }
180}
181
182impl TryFrom<&str> for Fact {
183 type Error = error::Token;
184
185 fn try_from(value: &str) -> Result<Self, Self::Error> {
186 Ok(biscuit_parser::parser::fact(value)
187 .finish()
188 .map(|(_, o)| o.into())
189 .map_err(biscuit_parser::error::LanguageError::from)?)
190 }
191}
192
193impl FromStr for Fact {
194 type Err = error::Token;
195
196 fn from_str(s: &str) -> Result<Self, Self::Err> {
197 Ok(biscuit_parser::parser::fact(s)
198 .finish()
199 .map(|(_, o)| o.into())
200 .map_err(biscuit_parser::error::LanguageError::from)?)
201 }
202}