//! Serialization constraint helpers. use std::{ convert::{TryFrom, TryInto}, ops::Deref, }; use crate::serialization::SerializationError; /// A `Vec` wrapper that ensures there is at least one `T` in the vector. /// /// You can initialize `AtLeastOne` using: /// ``` /// # use zebra_chain::serialization::{AtLeastOne, SerializationError}; /// # use std::convert::{TryFrom, TryInto}; /// # /// let v: AtLeastOne = vec![42].try_into()?; /// assert_eq!(v.as_slice(), [42]); /// /// let v: AtLeastOne = vec![42].as_slice().try_into()?; /// assert_eq!(v.as_slice(), [42]); /// /// let v: AtLeastOne = [42].try_into()?; /// assert_eq!(v.as_slice(), [42]); /// /// let v = AtLeastOne::::try_from(&[42])?; /// assert_eq!(v.as_slice(), [42]); /// # /// # Ok::<(), SerializationError>(()) /// ``` /// /// And access the inner vector via [deref coercion](https://doc.rust-lang.org/std/ops/trait.Deref.html#more-on-deref-coercion), /// an explicit conversion, or as a slice: /// ``` /// # use zebra_chain::serialization::AtLeastOne; /// # use std::convert::TryInto; /// # /// # let v: AtLeastOne = vec![42].try_into().unwrap(); /// # /// let first = v.iter().next().expect("AtLeastOne always has a first element"); /// assert_eq!(*first, 42); /// /// let s = v.as_slice(); /// # /// # assert_eq!(s, [42]); /// /// let mut m = v.into_vec(); /// # /// # assert_eq!(m.as_slice(), [42]); /// /// ``` /// /// `AtLeastOne` also re-implements some slice methods with different return /// types, to avoid redundant unwraps: /// ``` /// # use zebra_chain::serialization::AtLeastOne; /// # use std::convert::TryInto; /// # /// # let v: AtLeastOne = vec![42].try_into().unwrap(); /// # /// let first = v.first(); /// assert_eq!(*first, 42); /// /// let (first, rest) = v.split_first(); /// assert_eq!(*first, 42); /// assert!(rest.is_empty()); /// ``` #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub struct AtLeastOne { /// The inner vector, which must have at least one element. /// /// `inner` is private, so that it can't be modified in ways that break the /// type constraint. inner: Vec, } // CORRECTNESS // // All conversions to `AtLeastOne` must go through `TryFrom>`, // so that the type constraint is satisfied. impl TryFrom> for AtLeastOne { type Error = SerializationError; fn try_from(vec: Vec) -> Result { if vec.is_empty() { Err(SerializationError::Parse("expected at least one item")) } else { Ok(AtLeastOne { inner: vec }) } } } impl TryFrom<&Vec> for AtLeastOne where T: Clone, { type Error = SerializationError; fn try_from(vec: &Vec) -> Result { if vec.is_empty() { Err(SerializationError::Parse("expected at least one item")) } else { Ok(AtLeastOne { inner: vec.to_vec(), }) } } } impl TryFrom<&[T]> for AtLeastOne where T: Clone, { type Error = SerializationError; fn try_from(slice: &[T]) -> Result { slice.to_vec().try_into() } } // TODO: // - reject [T; 0] at compile time and impl From instead? impl TryFrom<[T; N]> for AtLeastOne where T: Clone, { type Error = SerializationError; fn try_from(slice: [T; N]) -> Result { slice.to_vec().try_into() } } // TODO: // - reject [T; 0] at compile time and impl From instead? // - remove when std is updated so that `TryFrom<&U>` is always implemented when // `TryFrom` impl TryFrom<&[T; N]> for AtLeastOne where T: Clone, { type Error = SerializationError; fn try_from(slice: &[T; N]) -> Result { slice.to_vec().try_into() } } // Deref and AsRef (but not DerefMut or AsMut, because that could break the constraint) impl Deref for AtLeastOne { type Target = Vec; fn deref(&self) -> &Self::Target { &self.inner } } impl AsRef<[T]> for AtLeastOne { fn as_ref(&self) -> &[T] { self.inner.as_ref() } } // Extracting one or more items impl From> for Vec { fn from(vec1: AtLeastOne) -> Self { vec1.inner } } // `IntoIterator` for `T` and `&mut T`, because iterators can't remove items impl IntoIterator for AtLeastOne { type Item = T; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> std::vec::IntoIter { self.inner.into_iter() } } impl AtLeastOne { /// Returns an iterator that allows modifying each value. pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { self.inner.iter_mut() } } impl AtLeastOne { /// Returns a new `AtLeastOne`, containing a single `item`. /// /// Skips the `TrustedPreallocate` memory denial of service checks. /// (`TrustedPreallocate` can not defend against a single item /// that causes a denial of service by itself.) pub fn from_one(item: T) -> AtLeastOne { AtLeastOne { inner: vec![item] } } /// Returns a reference to the inner vector. pub fn as_vec(&self) -> &Vec { &self.inner } /// Converts `self` into a vector without clones or allocation. /// /// The resulting vector can be converted back into `AtLeastOne` via `try_into`. pub fn into_vec(self) -> Vec { self.inner } /// Returns the first element. /// /// Unlike `Vec` or slice, `AtLeastOne` always has a first element. pub fn first(&self) -> &T { &self.inner[0] } /// Returns a mutable reference to the first element. /// /// Unlike `Vec` or slice, `AtLeastOne` always has a first element. pub fn first_mut(&mut self) -> &mut T { &mut self.inner[0] } /// Appends an element to the back of the collection. pub fn push(&mut self, element: T) { self.inner.push(element); } /// Returns the first and all the rest of the elements of the vector. /// /// Unlike `Vec` or slice, `AtLeastOne` always has a first element. pub fn split_first(&self) -> (&T, &[T]) { (&self.inner[0], &self.inner[1..]) } } // TODO: consider implementing `push`, `append`, and `Extend`, // because adding elements can't break the constraint. /// Create an initialized [`AtLeastOne`] instance. /// /// This macro is similar to the [`vec!`][`std::vec!`] macro, but doesn't support creating an empty /// `AtLeastOne` instance. /// /// # Security /// /// This macro must only be used in tests, because it skips the `TrustedPreallocate` memory /// denial of service checks. #[cfg(any(test, feature = "proptest-impl"))] #[macro_export] macro_rules! at_least_one { ($element:expr; 0) => ( compile_error!("At least one element needed to create an `AtLeastOne`") ); ($element:expr; $count:expr) => ( { as std::convert::TryInto<$crate::serialization::AtLeastOne<_>>>::try_into( vec![$element; $expr], ).expect("at least one element in `AtLeastOne<_>`") } ); ($($element:expr),+ $(,)?) => ( { as std::convert::TryInto<$crate::serialization::AtLeastOne<_>>>::try_into( vec![$($element),*], ).expect("at least one element in `AtLeastOne<_>`") } ); }