Skip to main content

substrate_data/schema/plain/
one_or_list.rs

1//! One value, or a list of them: `"a"` or `["a", "b"]` — what a format
2//! accepts where several will do (a field's accepted types, the files to
3//! pick one from).
4
5use crate::frame::{Packer, Unpacker};
6use crate::schema::{Reader, Schema, Shape};
7use crate::{Value, ValueRef};
8
9/// One value or several, read either way and written back the same way (one
10/// as itself). Never empty: an empty list is a problem.
11#[derive(Debug, Clone, PartialEq)]
12pub struct OneOrList<T>(pub Vec<T>);
13
14impl<T: Schema> Schema for OneOrList<T> {
15    fn shape() -> Shape {
16        Shape::List(T::shape)
17    }
18    fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<Self> {
19        match v {
20            ValueRef::List([]) => {
21                cx.problem("an empty list: at least one");
22                None
23            }
24            ValueRef::List(_) => Vec::<T>::read(v, cx).map(OneOrList),
25            _ => T::read(v, cx).map(|one| OneOrList(vec![one])),
26        }
27    }
28    fn write(&self) -> Value {
29        match self.0.as_slice() {
30            [one] => one.write(),
31            many => Value::List(many.iter().map(Schema::write).collect()),
32        }
33    }
34    /// In a frame it's a list (one or more), as its shape says.
35    fn pack(&self, p: &mut Packer) {
36        T::pack_list(&self.0, p);
37    }
38    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
39        T::unpack_list(u)
40            .filter(|items| !items.is_empty())
41            .map(OneOrList)
42    }
43}