use std::any::Any;
use vitaminc_protected::Protected;
use crate::{decrypt::Decrypt, IntoAad, Unspecified};
pub trait Decipher<'c>: Sized {
type Ok<T>
where
T: Send + 'c;
type Passthrough: Send + 'c;
fn map_ok<T, U, F>(ok: Self::Ok<T>, f: F) -> Self::Ok<U>
where
T: Send + 'c,
U: Send + 'c,
F: FnOnce(T) -> U;
fn decrypt_bytes<'a, V, A>(self, visitor: V, aad: A) -> Self::Ok<V::Value>
where
V: DecipherVisitor<'c> + Send + 'c,
A: IntoAad<'a>;
fn decrypt_seq<'a, V, A>(self, visitor: V, aad: A) -> Self::Ok<V::Value>
where
V: DecipherVisitor<'c> + Send + 'c,
A: IntoAad<'a>;
fn decrypt_map<'a, V, A>(self, visitor: V, aad: A) -> Self::Ok<V::Value>
where
V: DecipherVisitor<'c> + Send + 'c,
A: IntoAad<'a>;
fn decrypt_any<'a, V, A>(self, visitor: V, aad: A) -> Self::Ok<V::Value>
where
V: DecipherVisitor<'c> + Send + 'c,
A: IntoAad<'a>;
fn decrypt_passthrough(self) -> Self::Ok<Self::Passthrough>;
fn decrypt_option<'a, T, A>(self, aad: A) -> Self::Ok<Option<T>>
where
T: Decrypt<'c> + 'c,
A: IntoAad<'a>;
}
pub trait DecipherVisitor<'c>: Sized {
type Value: Send;
fn visit_bytes_vec(self, _data: Protected<Vec<u8>>) -> Result<Self::Value, Unspecified> {
Err(Unspecified)
}
fn visit_seq<A: SeqAccess<'c>>(self, _seq: A) -> Result<Self::Value, Unspecified> {
Err(Unspecified)
}
fn visit_map<A: MapAccess<'c>>(self, _map: A) -> Result<Self::Value, Unspecified> {
Err(Unspecified)
}
fn visit_none(self) -> Result<Self::Value, Unspecified> {
Err(Unspecified)
}
fn visit_passthrough(
self,
_value: Box<dyn Any + Send + 'static>,
) -> Result<Self::Value, Unspecified> {
Err(Unspecified)
}
}
pub trait SeqAccess<'c> {
type Error;
fn next_element<T: Decrypt<'c> + 'c>(&mut self) -> Result<Option<T>, Self::Error>;
}
pub trait MapAccess<'c> {
type Error: From<Unspecified>;
fn next_key(&mut self) -> Result<Option<String>, Self::Error>;
fn next_value<T: Decrypt<'c> + 'c>(&mut self) -> Result<T, Self::Error>;
fn next_passthrough(&mut self) -> Result<Box<dyn Any + Send + 'static>, Self::Error> {
Err(Unspecified.into())
}
fn next_entry<T: Decrypt<'c> + 'c>(&mut self) -> Result<Option<(String, T)>, Self::Error> {
match self.next_key()? {
Some(key) => self.next_value::<T>().map(|value| Some((key, value))),
None => Ok(None),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_util::MockMapAccess;
#[test]
fn next_entry_default_yields_every_entry_then_none() {
let mut map = MockMapAccess::new([("first", "a"), ("second", "b")]);
assert_eq!(
MapAccess::<'static>::next_entry::<String>(&mut map),
Ok(Some(("first".to_string(), "a".to_string())))
);
assert_eq!(
MapAccess::<'static>::next_entry::<String>(&mut map),
Ok(Some(("second".to_string(), "b".to_string())))
);
assert_eq!(
MapAccess::<'static>::next_entry::<String>(&mut map),
Ok(None)
);
}
#[test]
fn next_value_without_a_key_is_an_error() {
let mut map = MockMapAccess::new([("first", "a")]);
assert_eq!(
MapAccess::<'static>::next_value::<String>(&mut map),
Err(Unspecified)
);
}
#[test]
fn next_passthrough_default_rejects() {
let mut map = MockMapAccess::new([("first", "a")]);
assert_eq!(
MapAccess::<'static>::next_key(&mut map),
Ok(Some("first".to_string()))
);
assert!(MapAccess::<'static>::next_passthrough(&mut map).is_err());
}
#[test]
fn skipping_a_value_is_an_error() {
let mut map = MockMapAccess::new([("first", "a"), ("second", "b")]);
assert_eq!(
MapAccess::<'static>::next_key(&mut map),
Ok(Some("first".to_string()))
);
assert_eq!(MapAccess::<'static>::next_key(&mut map), Err(Unspecified));
}
}