ntdsextract2 1.2.1

Display contents of Active Directory database files (ntds.dit)
use std::marker::PhantomData;

use serde::{Deserialize, Serialize};

use crate::{win32_types::Rdn, SerializationType};

pub struct RdnSet<T: SerializationType>(Vec<Rdn>, PhantomData<T>);

impl<'a, T> From<Vec<&'a Rdn>> for RdnSet<T>
where
    T: SerializationType,
{
    fn from(value: Vec<&'a Rdn>) -> Self {
        Self(value.into_iter().cloned().collect(), PhantomData)
    }
}

impl<T> From<Vec<Rdn>> for RdnSet<T>
where
    T: SerializationType,
{
    fn from(value: Vec<Rdn>) -> Self {
        Self(value, PhantomData)
    }
}

impl<T> Serialize for RdnSet<T>
where
    T: SerializationType,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        T::serialize(self.0.iter().map(|rdn| rdn.to_string()), serializer)
    }
}

impl<'de, T> Deserialize<'de> for RdnSet<T>
where
    T: SerializationType,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        T::deserialize(deserializer)
    }
}

#[cfg(test)]
mod tests {
    use serde::Serialize;

    use crate::{win32_types::Rdn, CsvSerialization, JsonSerialization};

    use super::{RdnSet, SerializationType};

    #[derive(Serialize)]
    #[serde(bound = "T: SerializationType")]
    struct SampleRecord<T: SerializationType> {
        data: RdnSet<T>,
    }

    fn test_data<T>() -> SampleRecord<T>
    where
        T: SerializationType,
    {
        SampleRecord {
            data: RdnSet::<T>::from(vec![
                Rdn::try_from("a").unwrap(),
                Rdn::try_from("b").unwrap(),
                Rdn::try_from("c").unwrap(),
            ]),
        }
    }

    #[test]
    fn test_serialize_csv() {
        let mut wtr = csv::Writer::from_writer(vec![]);
        wtr.serialize(&test_data::<CsvSerialization>()).unwrap();

        let result = String::from_utf8(wtr.into_inner().unwrap()).unwrap();

        assert_eq!(
            result,
            r#"data
"a,b,c"
"#
        );
    }

    #[test]
    fn test_serialize_json() {
        let result = serde_json::to_string(&test_data::<JsonSerialization>()).unwrap();
        assert_eq!(result, r#"{"data":["a","b","c"]}"#);
    }
}