use crate::common::cbor::{
value, CborDecoder, CborDeserialize, CborEncoder, CborMaybeKnown, CborSerializationResult,
CborSerialize,
};
use std::any::type_name;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Upward<A, R = ()> {
Unknown(R),
Known(A),
}
impl<A, R> Upward<A, R> {
pub fn unwrap(self) -> A {
match self {
Self::Known(value) => value,
Self::Unknown(_) => panic!(
"called `Upward::<{}>::unwrap()` on an `Unknown` value",
type_name::<A>()
),
}
}
pub fn known(self) -> Option<A> {
Option::from(self)
}
pub fn as_known(&self) -> Option<&A> {
Option::from(self.as_ref_with_residual())
}
pub fn known_or_err(self) -> Result<A, UnknownDataError> {
self.known_or(UnknownDataError {
type_name: type_name::<A>(),
})
}
pub fn known_or<E>(self, error: E) -> Result<A, E> {
Option::from(self).ok_or(error)
}
pub fn known_or_else<E, F>(self, error: F) -> Result<A, E>
where
F: FnOnce(R) -> E,
{
match self {
Upward::Unknown(residual) => Err(error(residual)),
Upward::Known(output) => Ok(output),
}
}
pub fn is_known_and(self, f: impl FnOnce(A) -> bool) -> bool {
Option::from(self).is_some_and(f)
}
pub fn map<U, F>(self, f: F) -> Upward<U, R>
where
F: FnOnce(A) -> U,
{
match self {
Self::Known(x) => Upward::Known(f(x)),
Self::Unknown(r) => Upward::Unknown(r),
}
}
pub fn map_unknown<S, F>(self, f: F) -> Upward<A, S>
where
F: FnOnce(R) -> S,
{
match self {
Self::Known(x) => Upward::Known(x),
Self::Unknown(r) => Upward::Unknown(f(r)),
}
}
#[must_use = "if you don't need the returned value, use `if let` instead"]
pub fn map_or<U, F>(self, default: U, f: F) -> U
where
F: FnOnce(A) -> U,
{
match self {
Upward::Known(a) => f(a),
Upward::Unknown(_) => default,
}
}
pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
where
D: FnOnce() -> U,
F: FnOnce(A) -> U,
{
match self {
Upward::Known(t) => f(t),
Upward::Unknown(_) => default(),
}
}
pub const fn as_ref_with_residual(&self) -> Upward<&A, &R> {
match *self {
Self::Known(ref x) => Upward::Known(x),
Self::Unknown(ref r) => Upward::Unknown(r),
}
}
pub fn and_then<U, F>(self, f: F) -> Upward<U, R>
where
F: FnOnce(A) -> Upward<U, R>,
{
match self {
Upward::Unknown(r) => Upward::Unknown(r),
Upward::Known(x) => f(x),
}
}
}
pub type CborUpward<A> = Upward<A, value::Value>;
impl<T: CborSerialize> CborSerialize for CborUpward<T> {
fn serialize<C: CborEncoder>(&self, encoder: C) -> CborSerializationResult<()> {
match self {
Self::Unknown(value) => value.serialize(encoder),
Self::Known(value) => value.serialize(encoder),
}
}
}
impl<T: CborDeserialize> CborDeserialize for CborUpward<T> {
fn deserialize<C: CborDecoder>(decoder: C) -> CborSerializationResult<Self>
where
Self: Sized,
{
Ok(match T::deserialize_maybe_known(decoder)? {
CborMaybeKnown::Unknown(r) => Self::Unknown(r),
CborMaybeKnown::Known(val) => Self::Known(val),
})
}
}
impl<A> Upward<A> {
pub const fn as_ref(&self) -> Upward<&A> {
match *self {
Self::Known(ref x) => Upward::Known(x),
Self::Unknown(_) => Upward::Unknown(()),
}
}
}
impl<A, R, E> Upward<Result<A, E>, R> {
pub fn transpose(self) -> Result<Upward<A, R>, E> {
match self {
Upward::Known(Ok(x)) => Ok(Upward::Known(x)),
Upward::Known(Err(e)) => Err(e),
Upward::Unknown(r) => Ok(Upward::Unknown(r)),
}
}
}
impl<A> From<Option<A>> for Upward<A> {
fn from(value: Option<A>) -> Self {
if let Some(n) = value {
Self::Known(n)
} else {
Self::Unknown(())
}
}
}
impl<A, R> From<Upward<A, R>> for Option<A> {
fn from(value: Upward<A, R>) -> Self {
if let Upward::Known(n) = value {
Some(n)
} else {
None
}
}
}
impl<'de, A, R> serde::Deserialize<'de> for Upward<A, R>
where
A: serde::Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
A::deserialize(deserializer).map(Upward::Known)
}
}
impl<A, R> serde::Serialize for Upward<A, R>
where
A: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if let Upward::Known(a) = self {
a.serialize(serializer)
} else {
Err(serde::ser::Error::custom(format!(
"Serializing `Upward::<{}>::Unknown` is not supported",
type_name::<A>()
)))
}
}
}
#[derive(Debug, thiserror::Error)]
#[error("Encountered unknown data from the Node API on type `Upward::<{type_name}>::Unknown`, which is required to be known.")]
pub struct UnknownDataError {
type_name: &'static str,
}
impl UnknownDataError {
pub fn new(type_name: &'static str) -> Self {
Self { type_name }
}
}
impl<A> std::iter::FromIterator<Upward<A>> for Upward<Vec<A>> {
fn from_iter<T: IntoIterator<Item = Upward<A>>>(iter: T) -> Self {
let mut vec = Vec::new();
for a in iter {
if let Upward::Known(a) = a {
vec.push(a);
} else {
return Upward::Unknown(());
}
}
Upward::Known(vec)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_upward_from_iterator_all_known() {
let list = vec![Upward::Known(42); 50];
let res = list.into_iter().collect::<Upward<_>>().unwrap();
assert_eq!(vec![42; 50], res)
}
#[test]
fn test_upward_from_iterator_some_unknown() {
let mut list = vec![Upward::Known(42); 50];
list[25] = Upward::Unknown(());
let res = list.into_iter().collect::<Upward<_>>();
assert_eq!(Upward::Unknown(()), res)
}
}