| // Copyright 2023 Google LLC | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | use thiserror::Error; | 
 |  | 
 | /// A decodable type can be created from a byte buffer. | 
 | /// The type returned is separate (copied) from the buffer once decoded. | 
 | pub trait Decodable: ::core::marker::Sized { | 
 |     type Error; | 
 |  | 
 |     /// Decodes into a new object with the number of bytes that were decoded, or | 
 |     /// returns an error. | 
 |     fn decode(buf: &[u8]) -> ::core::result::Result<(Self, usize), Self::Error>; | 
 | } | 
 |  | 
 | /// An encodable type can write itself into a byte buffer. | 
 | pub trait Encodable { | 
 |     type Error; | 
 |  | 
 |     /// Returns the number of bytes necessary to encode |self|. | 
 |     fn encoded_len(&self) -> ::core::primitive::usize; | 
 |  | 
 |     /// Writes the encoded version of |self| at the start of |buf|. | 
 |     /// |buf| must be at least |self.encoded_len()| length. | 
 |     fn encode(&self, buf: &mut [u8]) -> ::core::result::Result<(), Self::Error>; | 
 | } | 
 |  | 
 | /// Generates an enum value where each variant can be converted into a constant in the given | 
 | /// raw_type. | 
 | /// | 
 | /// For example: | 
 | /// decodable_enum! { | 
 | ///     pub(crate) enum Color<u8, MyError, Variant> { | 
 | ///        Red = 1, | 
 | ///        Blue = 2, | 
 | ///        Green = 3, | 
 | ///     } | 
 | /// } | 
 | /// | 
 | /// Color::try_from(2) -> Color::Red | 
 | /// u8::from(&Color::Red) -> 1. | 
 | #[macro_export] | 
 | macro_rules! decodable_enum { | 
 |     ($(#[$meta:meta])* $visibility:vis enum $name:ident< | 
 |         $raw_type:ty, | 
 |         $error_type:ty, | 
 |         $error_path:ident | 
 |     > { | 
 |         $($(#[$variant_meta:meta])* $variant:ident = $val:expr),*, | 
 |     }) => { | 
 |         $(#[$meta])* | 
 |         #[derive( | 
 |             ::core::clone::Clone, | 
 |             ::core::marker::Copy, | 
 |             ::core::fmt::Debug, | 
 |             ::core::cmp::Eq, | 
 |             ::core::hash::Hash, | 
 |             ::core::cmp::PartialEq)] | 
 |         $visibility enum $name { | 
 |             $($(#[$variant_meta])* $variant = $val),* | 
 |         } | 
 |  | 
 |         impl $name { | 
 |             pub const VALUES : &'static [$raw_type] = &[$($val),*,]; | 
 |             pub const VARIANTS : &'static [$name] = &[$($name::$variant),*,]; | 
 |             pub fn name(&self) -> &'static ::core::primitive::str { | 
 |                 match self { | 
 |                     $($name::$variant => ::core::stringify!($variant)),* | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         impl ::core::convert::From<&$name> for $raw_type { | 
 |             fn from(v: &$name) -> $raw_type { | 
 |                 match v { | 
 |                     $($name::$variant => $val),*, | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         impl ::core::convert::TryFrom<$raw_type> for $name { | 
 |             type Error = $error_type; | 
 |  | 
 |             fn try_from(value: $raw_type) -> ::core::result::Result<Self, $error_type> { | 
 |                 match value { | 
 |                     $($val => ::core::result::Result::Ok($name::$variant)),*, | 
 |                     _ => ::core::result::Result::Err(<$error_type>::$error_path), | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | #[macro_export] | 
 | macro_rules! codable_as_bitmask { | 
 |     ($type:ty, $raw_type:ty) => { | 
 |         impl $type { | 
 |             pub fn from_bits(v: $raw_type) -> impl Iterator<Item = $type> { | 
 |                 (0..<$raw_type>::BITS) | 
 |                     .map(|bit| 1 << bit) | 
 |                     .filter(move |val| (v & val) != 0) | 
 |                     .filter_map(|val| val.try_into().ok()) | 
 |             } | 
 |  | 
 |             pub fn to_bits<'a>(it: impl Iterator<Item = &'a $type>) -> $raw_type { | 
 |                 it.fold(0, |acc, item| acc | Into::<$raw_type>::into(item)) | 
 |             } | 
 |         } | 
 |     }; | 
 | } | 
 |  | 
 | #[derive(Error, Debug, PartialEq)] | 
 | pub enum Error { | 
 |     #[error("Parameter is not valid: {0}")] | 
 |     InvalidParameter(String), | 
 |  | 
 |     #[error("Out-of-range enum value")] | 
 |     OutOfRange, | 
 |  | 
 |     #[error("Encoding buffer is too small")] | 
 |     BufferTooSmall, | 
 |  | 
 |     #[error("Buffer being decoded is invalid length")] | 
 |     UnexpectedDataLength, | 
 |  | 
 |     #[error("Unrecognized type for {0}: {1}")] | 
 |     UnrecognizedType(String, u8), | 
 | } |