signet 0.0.1

code signing tool
Documentation
use std::fmt;
use serde::de::{Deserialize, Deserializer, Error, Visitor};
use serde::de::{EnumAccess, Expected, Unexpected, VariantAccess};
use serde::ser::{Serialize, Serializer};
use ssh_key::{LineEnding, PrivateKey};
use crate::keychain::Key;

impl<'de> Deserialize<'de> for Key {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
        d.deserialize_enum("", &["SSH"], KeyVisitor)
    }
}

impl Serialize for Key {
    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        use serde::ser::Error;

        let Key::SSH(key) = self;

        let encoded = match key.to_openssh(LineEnding::default()) {
            Ok(key) => key,
            Err(e)  => return Err(S::Error::custom(e)),
        };

        s.serialize_newtype_variant::<String>("", 0, "SSH", &encoded)
    }
}

struct KeyVisitor;

impl<'de> Visitor<'de> for KeyVisitor {
    type Value = Key;

    fn visit_enum<A: EnumAccess<'de>>(self, data: A) -> Result<Self::Value, A::Error> {
        let (kind, var) = data.variant::<String>()?;

        let encoded = match kind.as_str() {
            "SSH" => var.newtype_variant::<String>()?,
            kind  => return Err(A::Error::unknown_variant(kind, &["SSH"])),
        };

        match PrivateKey::from_openssh(&encoded) {
            Ok(key) => Ok(Key::SSH(key)),
            Err(_)  => Err(invalid::<A>(&encoded, &self)),
        }
    }

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "an OpenSSH private key")
    }
}

fn invalid<'de, A: EnumAccess<'de>>(str: &str, expected: &dyn Expected) -> A::Error {
    A::Error::invalid_value(Unexpected::Str(str), expected)
}