use crate::misc::Length;
use crate::Asn1RawDer;
use picky_asn1::tag::{Tag, TagPeeker};
use serde::de::{Error, SeqAccess};
use serde::{de, ser};
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
#[derive(Debug, PartialEq, Eq)]
pub struct ApplicationTag<V: Debug + PartialEq, const T: u8>(pub V);
impl<V: Debug + PartialEq, const T: u8> ApplicationTag<V, T> {
pub fn from(value: V) -> Self {
Self(value)
}
}
impl<V: Clone + PartialEq + Debug, const T: u8> Clone for ApplicationTag<V, T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<'de, V: de::Deserialize<'de> + Debug + PartialEq, const T: u8> de::Deserialize<'de> for ApplicationTag<V, T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor<E, const T: u8>(PhantomData<E>);
impl<'de, E: de::Deserialize<'de> + Debug + PartialEq, const T: u8> de::Visitor<'de> for Visitor<E, T> {
type Value = E;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(&format!("A valid DER-encoded ApplicationTag{:02x}", T))
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
#[derive(Debug, serde::Deserialize)]
struct ApplicationTagInner<V: Debug> {
value: V,
}
let tag_peeker: TagPeeker = seq
.next_element()
.map_err(|e| A::Error::custom(format!("Cannot deserialize application tag: {:?}", e)))?
.ok_or_else(|| A::Error::missing_field("ApplicationTag"))?;
let tag = tag_peeker.next_tag;
if !tag.is_application() {
return Err(A::Error::custom(format!(
"Expected Application class tag but got: {:?}",
tag.class()
)));
}
if tag.number() != T {
return Err(A::Error::custom(format!(
"Expected Application number tag {} but got: {}",
T,
tag.number()
)));
}
let rest: ApplicationTagInner<E> = seq
.next_element()
.map_err(|e| A::Error::custom(format!("Cannot deserialize application tag inner value: {:?}", e)))?
.ok_or_else(|| A::Error::missing_field("ApplicationInnerValue"))?;
Ok(rest.value)
}
}
let inner = deserializer
.deserialize_enum("ApplicationTag", &["ApplicationTag"], Visitor::<V, T>(PhantomData))
.map_err(D::Error::custom)?;
Ok(Self(inner))
}
}
impl<V: ser::Serialize + Debug + PartialEq + Clone, const T: u8> ser::Serialize for ApplicationTag<V, T> {
fn serialize<S>(&self, serializer: S) -> Result<<S as ser::Serializer>::Ok, S::Error>
where
S: ser::Serializer,
{
use serde::ser::Error;
let mut buff = Vec::new();
{
let mut s = crate::Serializer::new_to_byte_buf(&mut buff);
self.0
.serialize(&mut s)
.map_err(|e| S::Error::custom(format!("Cannot serialize Application tag inner value: {:?}", e)))?;
}
let mut res = vec![Tag::application_constructed(T).inner()];
Length::serialize(buff.len(), &mut res)
.map_err(|e| S::Error::custom(format!("Cannot serialize Length: {:?}", e)))?;
res.extend_from_slice(&buff);
Asn1RawDer(res).serialize(serializer)
}
}
#[cfg(test)]
mod tests {
use crate::application_tag::ApplicationTag;
use picky_asn1::restricted_string::Utf8String;
use picky_asn1::wrapper::Utf8StringAsn1;
#[test]
fn test_application_tag() {
let expected_raw = vec![106, 13, 12, 11, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109];
let expected: ApplicationTag<Utf8StringAsn1, 10> = ApplicationTag::from(Utf8StringAsn1::from(
Utf8String::from_string("example.com".to_owned()).unwrap(),
));
let app_10: ApplicationTag<Utf8StringAsn1, 10> = crate::from_bytes(&expected_raw).unwrap();
let app_10_raw = crate::to_vec(&app_10).unwrap();
assert_eq!(expected, app_10);
assert_eq!(expected_raw, app_10_raw);
}
}