yatima_core/
meta.rs

1use core::fmt;
2
3use crate::{
4  ipld_error::IpldError,
5  name::Name,
6  position::Pos,
7};
8use sp_cid::Cid;
9use sp_ipld::Ipld;
10
11use sp_std::{
12  borrow::ToOwned,
13  boxed::Box,
14};
15
16use alloc::string::ToString;
17
18/// Metadata term containing only name, source position, and content id
19#[derive(PartialEq, Clone, Debug)]
20pub enum Meta {
21  Var(Pos, Name),
22  Lam(Pos, Name, Box<Meta>),
23  App(Pos, Box<(Meta, Meta)>),
24  All(Pos, Name, Box<(Meta, Meta)>),
25  Slf(Pos, Name, Box<Meta>),
26  Dat(Pos, Box<Meta>),
27  Cse(Pos, Box<Meta>),
28  Ref(Pos, Name, Cid),
29  Let(Pos, Name, Box<(Meta, Meta, Meta)>),
30  Typ(Pos),
31  Ann(Pos, Box<(Meta, Meta)>),
32  Lit(Pos),
33  LTy(Pos),
34  Opr(Pos),
35  Rec(Pos),
36}
37
38impl Meta {
39  /// Converts a metadata term into an IPLD object
40  pub fn to_ipld(&self) -> Ipld {
41    match self {
42      Self::Var(pos, nam) => Ipld::List(vec![
43        Ipld::Integer(0),
44        pos.to_ipld(),
45        Ipld::String(nam.to_string()),
46      ]),
47      Self::Lam(pos, nam, bod) => Ipld::List(vec![
48        Ipld::Integer(1),
49        pos.to_ipld(),
50        Ipld::String(nam.to_string()),
51        bod.to_ipld(),
52      ]),
53      Self::App(pos, fun_arg) => {
54        let (fun, arg) = (*fun_arg).as_ref();
55        Ipld::List(vec![
56          Ipld::Integer(2),
57          pos.to_ipld(),
58          fun.to_ipld(),
59          arg.to_ipld(),
60        ])
61      }
62      Self::All(pos, nam, dom_img) => {
63        let (dom, img) = (*dom_img).as_ref();
64        Ipld::List(vec![
65          Ipld::Integer(3),
66          pos.to_ipld(),
67          Ipld::String(nam.to_string()),
68          dom.to_ipld(),
69          img.to_ipld(),
70        ])
71      }
72      Self::Slf(pos, nam, bod) => Ipld::List(vec![
73        Ipld::Integer(4),
74        pos.to_ipld(),
75        Ipld::String(nam.to_string()),
76        bod.to_ipld(),
77      ]),
78      Self::Dat(pos, bod) => {
79        Ipld::List(vec![Ipld::Integer(5), pos.to_ipld(), bod.to_ipld()])
80      }
81      Self::Cse(pos, bod) => {
82        Ipld::List(vec![Ipld::Integer(6), pos.to_ipld(), bod.to_ipld()])
83      }
84      Self::Ref(pos, nam, cid) => Ipld::List(vec![
85        Ipld::Integer(7),
86        pos.to_ipld(),
87        Ipld::String(nam.to_string()),
88        Ipld::Link(*cid),
89      ]),
90      Self::Let(pos, nam, typ_exp_bod) => {
91        let (typ, exp, bod) = (*typ_exp_bod).as_ref();
92        Ipld::List(vec![
93          Ipld::Integer(8),
94          pos.to_ipld(),
95          Ipld::String(nam.to_string()),
96          typ.to_ipld(),
97          exp.to_ipld(),
98          bod.to_ipld(),
99        ])
100      }
101      Self::Typ(pos) => Ipld::List(vec![Ipld::Integer(9), pos.to_ipld()]),
102      Self::Ann(pos, typ_exp) => {
103        let (typ, exp) = (*typ_exp).as_ref();
104        Ipld::List(vec![
105          Ipld::Integer(10),
106          pos.to_ipld(),
107          typ.to_ipld(),
108          exp.to_ipld(),
109        ])
110      }
111      Self::Lit(pos) => Ipld::List(vec![Ipld::Integer(11), pos.to_ipld()]),
112      Self::LTy(pos) => Ipld::List(vec![Ipld::Integer(12), pos.to_ipld()]),
113      Self::Opr(pos) => Ipld::List(vec![Ipld::Integer(13), pos.to_ipld()]),
114      Self::Rec(pos) => Ipld::List(vec![Ipld::Integer(14), pos.to_ipld()]),
115    }
116  }
117
118  /// Converts an IPLD object into a metadata term
119  pub fn from_ipld(ipld: &Ipld) -> Result<Self, IpldError> {
120    match ipld {
121      Ipld::List(xs) => match xs.as_slice() {
122        [Ipld::Integer(0), pos, Ipld::String(nam)] => {
123          let pos = Pos::from_ipld(pos)?;
124          Ok(Meta::Var(pos, Name::from(nam.clone())))
125        }
126        [Ipld::Integer(1), pos, Ipld::String(nam), bod] => {
127          let pos = Pos::from_ipld(pos)?;
128          let bod = Meta::from_ipld(bod)?;
129          Ok(Meta::Lam(pos, Name::from(nam.clone()), Box::new(bod)))
130        }
131        [Ipld::Integer(2), pos, fun, arg] => {
132          let pos = Pos::from_ipld(pos)?;
133          let fun = Meta::from_ipld(fun)?;
134          let arg = Meta::from_ipld(arg)?;
135          Ok(Meta::App(pos, Box::new((fun, arg))))
136        }
137        [Ipld::Integer(3), pos, Ipld::String(nam), dom, img] => {
138          let pos = Pos::from_ipld(pos)?;
139          let dom = Meta::from_ipld(dom)?;
140          let img = Meta::from_ipld(img)?;
141          Ok(Meta::All(pos, Name::from(nam.clone()), Box::new((dom, img))))
142        }
143        [Ipld::Integer(4), pos, Ipld::String(nam), bod] => {
144          let pos = Pos::from_ipld(pos)?;
145          let bod = Meta::from_ipld(bod)?;
146          Ok(Meta::Slf(pos, Name::from(nam.clone()), Box::new(bod)))
147        }
148        [Ipld::Integer(5), pos, bod] => {
149          let pos = Pos::from_ipld(pos)?;
150          let bod = Meta::from_ipld(bod)?;
151          Ok(Meta::Dat(pos, Box::new(bod)))
152        }
153        [Ipld::Integer(6), pos, bod] => {
154          let pos = Pos::from_ipld(pos)?;
155          let bod = Meta::from_ipld(bod)?;
156          Ok(Meta::Cse(pos, Box::new(bod)))
157        }
158        [Ipld::Integer(7), pos, Ipld::String(nam), Ipld::Link(cid)] => {
159          let pos = Pos::from_ipld(pos)?;
160          Ok(Meta::Ref(pos, Name::from(nam.clone()), *cid))
161        }
162        [Ipld::Integer(8), pos, Ipld::String(nam), typ, exp, bod] => {
163          let pos = Pos::from_ipld(pos)?;
164          let typ = Meta::from_ipld(typ)?;
165          let exp = Meta::from_ipld(exp)?;
166          let bod = Meta::from_ipld(bod)?;
167          Ok(Meta::Let(pos, Name::from(nam.clone()), Box::new((typ, exp, bod))))
168        }
169        [Ipld::Integer(9), pos] => {
170          let pos = Pos::from_ipld(pos)?;
171          Ok(Meta::Typ(pos))
172        }
173        [Ipld::Integer(10), pos, typ, exp] => {
174          let pos = Pos::from_ipld(pos)?;
175          let typ = Meta::from_ipld(typ)?;
176          let exp = Meta::from_ipld(exp)?;
177          Ok(Meta::Ann(pos, Box::new((typ, exp))))
178        }
179        [Ipld::Integer(11), pos] => {
180          let pos = Pos::from_ipld(pos)?;
181          Ok(Self::Lit(pos))
182        }
183        [Ipld::Integer(12), pos] => {
184          let pos = Pos::from_ipld(pos)?;
185          Ok(Self::LTy(pos))
186        }
187        [Ipld::Integer(13), pos] => {
188          let pos = Pos::from_ipld(pos)?;
189          Ok(Self::Opr(pos))
190        }
191        [Ipld::Integer(14), pos] => {
192          let pos = Pos::from_ipld(pos)?;
193          Ok(Self::Rec(pos))
194        }
195        xs => Err(IpldError::Meta(Ipld::List(xs.to_owned()))),
196      },
197      xs => Err(IpldError::Meta(xs.to_owned())),
198    }
199  }
200}
201
202impl fmt::Display for Meta {
203  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204    use Meta::*;
205    match self.clone() {
206      Var(_, name) => write!(f, "Var({})", name),
207      Lam(_, name, b) => write!(f, "Lam({}, {}", name, *b),
208      App(_, b) => write!(f, "App({}, {})", (*b).0, (*b).1),
209      All(_, name, b) => write!(f, "All({}, {}, {})", name, (*b).0, (*b).1),
210      Slf(_, name, b) => writeln!(f, "Slf({}, {})", name, *b),
211      Dat(_, b) => write!(f, "Dat({})", *b),
212      Cse(_, b) => write!(f, "Cse({})", *b),
213      Ref(_, name, cid) => write!(f, "Ref({}, {})", name, cid),
214      Let(_, name, b) => {
215        write!(f, "Let({}, {}, {}, {})", name, (*b).0, (*b).1, (*b).2)
216      }
217      Typ(_) => write!(f, "Typ"),
218      Ann(_, b) => write!(f, "Ann({}, {})", (*b).0, (*b).1),
219      Lit(_) => write!(f, "Lit"),
220      LTy(_) => write!(f, "LTy"),
221      Opr(_) => write!(f, "Opr"),
222      Rec(_) => write!(f, "Rec"),
223    }
224  }
225}
226
227#[cfg(test)]
228pub mod tests {
229  use super::*;
230  use quickcheck::{
231    Arbitrary,
232    Gen,
233  };
234
235  use crate::term::Term;
236
237  impl Arbitrary for Meta {
238    fn arbitrary(g: &mut Gen) -> Self {
239      let term: Term = Arbitrary::arbitrary(g);
240      let (_, meta) = term.embed();
241      meta
242    }
243  }
244
245  #[quickcheck]
246  fn meta_ipld(x: Meta) -> bool {
247    match Meta::from_ipld(&x.to_ipld()) {
248      Ok(y) => x == y,
249      _ => false,
250    }
251  }
252}