//! Types for creating digests with the `ring` cryptography library

use super::DigestCreate;

/// A Sha256 digest backed by ring
#[derive(Clone)]
pub struct Sha256 {
    ctx: ring::digest::Context,
}

/// A Sha384 digest backed by ring
#[derive(Clone)]
pub struct Sha384 {
    ctx: ring::digest::Context,
}

/// A Sha512 digest backed by ring
#[derive(Clone)]
pub struct Sha512 {
    ctx: ring::digest::Context,
}

impl Sha256 {
    /// Create a new empty digest
    pub fn new() -> Self {
        Self::default()
    }

    /// Extract the context
    pub fn into_inner(self) -> ring::digest::Context {
        self.ctx
    }
}

impl Default for Sha256 {
    fn default() -> Self {
        Sha256 {
            ctx: ring::digest::Context::new(&ring::digest::SHA256),
        }
    }
}

impl Sha384 {
    /// Create a new empty digest
    pub fn new() -> Self {
        Self::default()
    }

    /// Extract the context
    pub fn into_inner(self) -> ring::digest::Context {
        self.ctx
    }
}

impl Default for Sha384 {
    fn default() -> Self {
        Sha384 {
            ctx: ring::digest::Context::new(&ring::digest::SHA384),
        }
    }
}

impl Sha512 {
    /// Create a new empty digest
    pub fn new() -> Self {
        Self::default()
    }

    /// Extract the context
    pub fn into_inner(self) -> ring::digest::Context {
        self.ctx
    }
}

impl Default for Sha512 {
    fn default() -> Self {
        Sha512 {
            ctx: ring::digest::Context::new(&ring::digest::SHA512),
        }
    }
}

fn create(mut context: ring::digest::Context, input: &[u8]) -> String {
    use base64::prelude::*;

    context.update(input);
    let digest = context.finish();
    BASE64_STANDARD.encode(digest.as_ref())
}

impl DigestCreate for Sha256 {
    const NAME: &'static str = "SHA-256";

    fn compute(&mut self, input: &[u8]) -> String {
        create(self.ctx.clone(), input)
    }
}

impl DigestCreate for Sha384 {
    const NAME: &'static str = "SHA-384";

    fn compute(&mut self, input: &[u8]) -> String {
        create(self.ctx.clone(), input)
    }
}

impl DigestCreate for Sha512 {
    const NAME: &'static str = "SHA-512";

    fn compute(&mut self, input: &[u8]) -> String {
        create(self.ctx.clone(), input)
    }
}
