1use core::fmt;
2
3use crate::{
4 ipld_error::IpldError,
5 meta::Meta,
6 name::Name,
7 position::Pos,
8};
9
10use sp_cid::Cid;
11use sp_ipld::{
12 dag_cbor::cid,
13 Ipld,
14};
15
16use sp_std::{
17 borrow::ToOwned,
18 vec::Vec,
19};
20
21use alloc::string::{
22 String,
23 ToString,
24};
25
26#[derive(PartialEq, Clone, Debug)]
28pub struct Package {
29 pub pos: Pos,
30 pub name: Name,
31 pub imports: Vec<Import>,
32 pub index: Index,
33}
34
35#[derive(PartialEq, Clone, Debug)]
37pub struct Import {
38 pub cid: Cid,
39 pub name: Name,
40 pub alias: Name,
41 pub with: Vec<Name>,
42}
43
44#[derive(PartialEq, Clone, Debug)]
46pub struct Index(pub Vec<(Name, Cid)>);
47
48#[derive(PartialEq, Clone, Debug)]
50pub struct Entry {
51 pub pos: Pos,
52 pub type_anon: Cid,
53 pub term_anon: Cid,
54 pub type_meta: Meta,
55 pub term_meta: Meta,
56}
57
58impl Entry {
59 pub fn to_ipld(&self) -> Ipld {
61 Ipld::List(vec![
62 self.pos.to_ipld(),
63 Ipld::Link(self.type_anon),
64 Ipld::Link(self.term_anon),
65 self.type_meta.to_ipld(),
66 self.term_meta.to_ipld(),
67 ])
68 }
69
70 pub fn from_ipld(ipld: &Ipld) -> Result<Self, IpldError> {
72 match ipld {
73 Ipld::List(xs) => match xs.as_slice() {
74 #[rustfmt::skip]
75 [ pos,
76 Ipld::Link(type_anon),
77 Ipld::Link(term_anon),
78 type_meta,
79 term_meta,
80 ] => {
81 let pos = Pos::from_ipld(pos)?;
82 let type_meta = Meta::from_ipld(type_meta)?;
83 let term_meta = Meta::from_ipld(term_meta)?;
84 Ok(Entry {
85 pos,
86 type_anon: *type_anon,
87 term_anon: *term_anon,
88 type_meta,
89 term_meta
90 })
91 }
92 xs => Err(IpldError::Entry(Ipld::List(xs.to_owned()))),
93 },
94 xs => Err(IpldError::Entry(xs.to_owned())),
95 }
96 }
97
98 pub fn cid(&self) -> Cid { cid(&self.to_ipld()) }
100}
101
102impl fmt::Display for Entry {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 writeln!(f, "Entry")?;
105 writeln!(f, " Type ({}):", self.type_anon)?;
106 writeln!(f, " {}", self.type_meta)?;
107 writeln!(f, " Term ({}):", self.term_anon)?;
108 writeln!(f, " {}", self.term_meta)?;
109 Ok(())
110 }
111}
112
113impl Index {
114 pub fn to_ipld(&self) -> Ipld {
116 Ipld::List(
117 self
118 .0
119 .iter()
120 .map(|(k, v)| {
121 Ipld::List(vec![Ipld::String(k.to_string()), Ipld::Link(*v)])
122 })
123 .collect(),
124 )
125 }
126
127 pub fn from_ipld(ipld: &Ipld) -> Result<Self, IpldError> {
129 match ipld {
130 Ipld::List(xs) => {
131 let mut res: Vec<(Name, Cid)> = Vec::new();
132 for x in xs {
133 match x {
134 Ipld::List(xs) => match xs.as_slice() {
135 [Ipld::String(n), Ipld::Link(cid)] => {
136 res.push((Name::from(n.clone()), *cid));
137 }
138 xs => {
139 return Err(IpldError::IndexEntry(Ipld::List(xs.to_owned())));
140 }
141 },
142 x => {
143 return Err(IpldError::IndexEntry(x.to_owned()));
144 }
145 }
146 }
147 Ok(Index(res))
148 }
149 xs => Err(IpldError::Index(xs.to_owned())),
150 }
151 }
152
153 pub fn keys(&self) -> Vec<Name> {
155 let mut res = Vec::new();
156 for (n, _) in &self.0 {
157 res.push(n.clone())
158 }
159 res
160 }
161}
162
163impl fmt::Display for Index {
164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165 writeln!(f, "Exporting")?;
166 for (n, cid) in self.0.clone() {
167 writeln!(f, " {} ({})", n, cid)?;
168 }
169 Ok(())
170 }
171}
172
173impl Import {
174 pub fn to_ipld(&self) -> Ipld {
176 Ipld::List(vec![
177 Ipld::Link(self.cid),
178 Ipld::String(self.name.to_string()),
179 Ipld::String(self.alias.to_string()),
180 Ipld::List(
181 self.with.iter().map(|x| Ipld::String(x.to_string())).collect(),
182 ),
183 ])
184 }
185
186 pub fn from_ipld(ipld: &Ipld) -> Result<Self, IpldError> {
188 match ipld {
189 Ipld::List(xs) => match xs.as_slice() {
190 [Ipld::Link(cid), Ipld::String(name), Ipld::String(alias), Ipld::List(with)] =>
191 {
192 let mut res: Vec<String> = Vec::new();
193 for w in with {
194 match w {
195 Ipld::String(w) => {
196 res.push(w.clone());
197 }
198 w => return Err(IpldError::ImportEntry(w.to_owned())),
199 }
200 }
201 Ok(Self {
202 cid: *cid,
203 name: Name::from(name.clone()),
204 alias: Name::from(alias.clone()),
205 with: res.iter().cloned().map(Name::from).collect(),
206 })
207 }
208 xs => Err(IpldError::Import(Ipld::List(xs.to_owned()))),
209 },
210 xs => Err(IpldError::Import(xs.to_owned())),
211 }
212 }
213}
214
215impl fmt::Display for Import {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 if self.alias.is_empty() {
218 writeln!(f, "Importing from {} ({})", self.name, self.cid)?;
219 }
220 else {
221 writeln!(
222 f,
223 "Importing from {} as {} ({})",
224 self.name, self.alias, self.cid
225 )?;
226 }
227 for with_ident in self.with.clone() {
228 writeln!(f, " {}", with_ident)?;
229 }
230 Ok(())
231 }
232}
233
234pub fn import_alias(name: Name, import: &Import) -> Name {
236 if import.with.iter().any(|x| *x == name) {
237 if import.alias.is_empty() {
238 name
239 }
240 else {
241 Name::from(format!("{}.{}", import.alias, name))
242 }
243 }
244 else {
245 Name::from(format!("{}.{}", import.name, name))
246 }
247}
248
249impl Package {
250 pub fn to_ipld(&self) -> Ipld {
252 Ipld::List(vec![
253 self.pos.to_ipld(),
254 Ipld::String(self.name.to_string()),
255 Ipld::List(self.imports.iter().map(Import::to_ipld).collect()),
256 self.index.to_ipld(),
257 ])
258 }
259
260 pub fn from_ipld(ipld: &Ipld) -> Result<Self, IpldError> {
262 match ipld {
263 Ipld::List(xs) => match xs.as_slice() {
264 [pos, Ipld::String(name), Ipld::List(is), index] => {
265 let pos: Pos = Pos::from_ipld(pos)?;
266 let mut imports: Vec<Import> = Vec::new();
267 for i in is {
268 let i = Import::from_ipld(i)?;
269 imports.push(i);
270 }
271 let index = Index::from_ipld(index)?;
272 Ok(Package { pos, name: Name::from(name.clone()), imports, index })
273 }
274 xs => Err(IpldError::Package(Ipld::List(xs.to_owned()))),
275 },
276 xs => Err(IpldError::Package(xs.to_owned())),
277 }
278 }
279
280 pub fn cid(&self) -> Cid { cid(&self.to_ipld()) }
282}
283
284impl fmt::Display for Package {
285 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286 writeln!(f, "Package \"{}\"", self.name)?;
287 for i in self.imports.clone() {
288 writeln!(f, "{}", i)?;
289 }
290 writeln!(f, "{}", self.index)?;
291 Ok(())
292 }
293}
294
295#[cfg(test)]
296pub mod tests {
297 use super::*;
298 use quickcheck::{
299 Arbitrary,
300 Gen,
301 };
302
303 use crate::{
304 defs::tests::arbitrary_def,
305 term::tests::arbitrary_name,
306 tests::arbitrary_cid,
307 };
308
309 impl Arbitrary for Entry {
310 fn arbitrary(g: &mut Gen) -> Self { arbitrary_def(g).1 }
311 }
312
313 impl Arbitrary for Index {
314 fn arbitrary(g: &mut Gen) -> Self {
315 let vec: Vec<()> = Arbitrary::arbitrary(g);
316 Index(
317 vec
318 .into_iter()
319 .map(|_| (arbitrary_name(g), arbitrary_cid(g)))
320 .collect(),
321 )
322 }
323 }
324
325 impl Arbitrary for Import {
326 fn arbitrary(g: &mut Gen) -> Self {
327 let vec: Vec<()> = Arbitrary::arbitrary(g);
328 let vec: Vec<Name> = vec.into_iter().map(|_| arbitrary_name(g)).collect();
329 Self {
330 name: Name::from("Test"),
331 cid: arbitrary_cid(g),
332 alias: arbitrary_name(g),
333 with: vec,
334 }
335 }
336 }
337
338 impl Arbitrary for Package {
339 fn arbitrary(g: &mut Gen) -> Self {
340 Package {
341 pos: Pos::None,
342 name: arbitrary_name(g),
343 imports: Arbitrary::arbitrary(g),
344 index: Arbitrary::arbitrary(g),
345 }
346 }
347 }
348
349 #[quickcheck]
350 fn entry_ipld(x: Entry) -> bool {
351 match Entry::from_ipld(&x.to_ipld()) {
352 Ok(y) => x == y,
353 _ => false,
354 }
355 }
356 #[quickcheck]
357 fn index_ipld(x: Index) -> bool {
358 match Index::from_ipld(&x.to_ipld()) {
359 Ok(y) => x == y,
360 _ => false,
361 }
362 }
363 #[quickcheck]
364 fn import_ipld(x: Import) -> bool {
365 match Import::from_ipld(&x.to_ipld()) {
366 Ok(y) => x == y,
367 _ => false,
368 }
369 }
370 #[quickcheck]
371 fn package_ipld(x: Package) -> bool {
372 match Package::from_ipld(&x.to_ipld()) {
373 Ok(y) => x == y,
374 _ => false,
375 }
376 }
377}