taler-rust

GNU Taler code in Rust. Largely core banking integrations.
Log | Files | Refs | Submodules | README | LICENSE

base32.rs (3708B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2024, 2025, 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 
     17 use std::{borrow::Cow, fmt::Display, ops::Deref, str::FromStr};
     18 
     19 use rand::{TryRng, rngs::SysRng};
     20 use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
     21 
     22 use crate::encoding::base32::{Base32Error, decode_static, encode_static, encoded_buf_len};
     23 
     24 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
     25 pub struct Base32<const L: usize>([u8; L]);
     26 
     27 impl<const L: usize> Base32<L> {
     28     pub fn rand() -> Self {
     29         Self(rand::random())
     30     }
     31 
     32     pub fn secure_rand() -> Self {
     33         let mut array = [0; L];
     34         SysRng.try_fill_bytes(&mut array).unwrap();
     35         Self(array)
     36     }
     37 }
     38 
     39 impl<const L: usize> From<[u8; L]> for Base32<L> {
     40     fn from(array: [u8; L]) -> Self {
     41         Self(array)
     42     }
     43 }
     44 
     45 impl<const L: usize> Deref for Base32<L> {
     46     type Target = [u8; L];
     47 
     48     fn deref(&self) -> &Self::Target {
     49         &self.0
     50     }
     51 }
     52 
     53 impl<const L: usize> FromStr for Base32<L> {
     54     type Err = Base32Error<L>;
     55 
     56     fn from_str(s: &str) -> Result<Self, Self::Err> {
     57         Ok(Self(decode_static(s.as_bytes())?))
     58     }
     59 }
     60 
     61 impl<const L: usize> Display for Base32<L> {
     62     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     63         let mut buff = vec![0u8; encoded_buf_len(L)]; // TODO use a stack allocated buffer when supported
     64         f.write_str(encode_static(&self.0, &mut buff))
     65     }
     66 }
     67 
     68 impl<const L: usize> std::fmt::Debug for Base32<L> {
     69     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     70         Display::fmt(&self, f)
     71     }
     72 }
     73 
     74 impl<const L: usize> Serialize for Base32<L> {
     75     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     76     where
     77         S: Serializer,
     78     {
     79         serializer.serialize_str(&self.to_string())
     80     }
     81 }
     82 
     83 impl<'de, const L: usize> Deserialize<'de> for Base32<L> {
     84     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     85     where
     86         D: Deserializer<'de>,
     87     {
     88         let raw = Cow::<str>::deserialize(deserializer)?;
     89         Self::from_str(&raw).map_err(D::Error::custom)
     90     }
     91 }
     92 
     93 impl<'a, const L: usize> TryFrom<&'a [u8]> for Base32<L> {
     94     type Error = Base32Error<L>;
     95 
     96     fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
     97         Ok(Self(
     98             value
     99                 .try_into()
    100                 .map_err(|_| Base32Error::Length(value.len()))?,
    101         ))
    102     }
    103 }
    104 
    105 impl<const L: usize> sqlx::Type<sqlx::Postgres> for Base32<L> {
    106     fn type_info() -> sqlx::postgres::PgTypeInfo {
    107         <&[u8]>::type_info()
    108     }
    109 }
    110 
    111 impl<'q, const L: usize> sqlx::Encode<'q, sqlx::Postgres> for Base32<L> {
    112     fn encode_by_ref(
    113         &self,
    114         buf: &mut sqlx::postgres::PgArgumentBuffer,
    115     ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
    116         self.0.encode_by_ref(buf)
    117     }
    118 }
    119 
    120 impl<'r, const L: usize> sqlx::Decode<'r, sqlx::Postgres> for Base32<L> {
    121     fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> {
    122         let array = <[u8; L]>::decode(value)?;
    123         Ok(Self(array))
    124     }
    125 }