jsonwebkey 0.4.0

JSON Web Key (JWK) (de)serialization, generation, and conversion.
Documentation
use serde::{
    de::{self, Deserialize, Deserializer},
    ser::{Serialize, SerializeSeq, Serializer},
};

macro_rules! impl_key_ops {
    ($(($key_op:ident, $const_name:ident, $i:literal)),+,) => {
        bitflags::bitflags! {
            #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
            pub struct KeyOps: u16 {
                $(const $const_name = $i;)*
            }
        }

        impl Serialize for KeyOps {
            fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
                let mut seq = s.serialize_seq(Some(self.bits().count_ones() as usize))?;
                $(
                    if self.contains(KeyOps::$const_name) {
                        seq.serialize_element(stringify!($key_op))?;
                    }
                )+
                seq.end()
            }
        }

        impl<'de> Deserialize<'de> for KeyOps {
            fn deserialize<D: Deserializer<'de>>(d: D) -> Result<KeyOps, D::Error> {
                let op_strs: Vec<String> = Deserialize::deserialize(d)?;
                let mut ops = KeyOps::default();
                for op_str in op_strs {
                    $(
                        if op_str == stringify!($key_op) {
                            ops |= KeyOps::$const_name;
                            continue;
                        }
                    )+
                        return Err(de::Error::custom(&format!("invalid key op: `{}`", op_str)));
                }
                Ok(ops)
            }
        }
    };
}

#[rustfmt::skip]
impl_key_ops!(
    (sign,       SIGN,        0b00000001),
    (verify,     VERIFY,      0b00000010),
    (encrypt,    ENCRYPT,     0b00000100),
    (decrypt,    DECRYPT,     0b00001000),
    (wrapKey,    WRAP_KEY,    0b00010000),
    (unwrapKey,  UNWRAP_KEY,  0b00100000),
    (deriveKey,  DERIVE_KEY,  0b01000000),
    (deriveBits, DERIVE_BITS, 0b10000000),
);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn deserialize_invalid() {
        let result: Result<KeyOps, _> = serde_json::from_str(r#"["unknown"]"#);
        assert!(result.is_err());
    }

    #[test]
    fn serialize() {
        let ops = KeyOps::SIGN | KeyOps::DERIVE_BITS;
        let json = serde_json::to_string(&ops).unwrap();
        assert_eq!(json, r#"["sign","deriveBits"]"#)
    }
}