use base64::{Engine, prelude::BASE64_STANDARD};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct Nonce {
first: [Option<u8>; 32],
second: [Option<u8>; 32],
}
impl TryFrom<String> for Nonce {
type Error = base64::DecodeSliceError;
fn try_from(value: String) -> Result<Self, Self::Error> {
<Self as TryFrom<&str>>::try_from(&value)
}
}
impl TryFrom<&str> for Nonce {
type Error = base64::DecodeSliceError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let mut buffer = [0; 64];
let written = BASE64_STANDARD.decode_slice(value, &mut buffer)?;
let mut output = [None; 64];
for (slot, byte) in output.iter_mut().zip(buffer[..written].iter()) {
*slot = Some(*byte);
}
let mut first = [None; 32];
first.copy_from_slice(&output[..32]);
let mut second = [None; 32];
second.copy_from_slice(&output[32..]);
Ok(Self { first, second })
}
}
impl From<Nonce> for String {
fn from(value: Nonce) -> Self {
let mut buffer = String::new();
let mut index = 0;
let mut payload = [0; 64];
for (slot, maybe_byte) in payload
.iter_mut()
.zip(value.first.iter().chain(value.second.iter()))
{
if let Some(byte) = maybe_byte {
*slot = *byte;
index += 1;
}
}
let trimmed_payload = &payload[..index];
BASE64_STANDARD.encode_string(trimmed_payload, &mut buffer);
buffer
}
}