taler-rust

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

utils.rs (3118B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2025 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::{fmt::Debug, ops::Deref};
     18 
     19 use jiff::{Timestamp, civil::Date, tz::TimeZone};
     20 
     21 #[derive(Clone, PartialEq, Eq)]
     22 pub struct InlineStr<const LEN: usize> {
     23     /// Len of ascii string in buf
     24     len: u8,
     25     /// Buffer of ascii bytes, left adjusted and zero padded
     26     // TODO use std::ascii::Char when stable
     27     buf: [u8; LEN],
     28 }
     29 
     30 impl<const LEN: usize> InlineStr<LEN> {
     31     /// Create an inlined string from a slice
     32     #[inline]
     33     pub fn copy_from_slice(slice: &[u8]) -> Self {
     34         let len = slice.len();
     35         let mut buf = [0; LEN];
     36         buf[..len].copy_from_slice(slice);
     37         debug_assert!(buf.is_ascii());
     38         Self {
     39             len: len as u8,
     40             buf,
     41         }
     42     }
     43 
     44     /// Create an inlined string from a string
     45     /// Return none if too long
     46     #[inline]
     47     pub fn try_from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Option<Self> {
     48         let mut len = 0;
     49         let mut buf = [0; LEN];
     50         for byte in iter {
     51             *buf.get_mut(len)? = byte;
     52             len += 1;
     53         }
     54         debug_assert!(buf.is_ascii());
     55         Some(Self {
     56             len: len as u8,
     57             buf,
     58         })
     59     }
     60 
     61     /// # Safety
     62     /// You must only write valid ASCII chars
     63     #[inline]
     64     pub unsafe fn deref_mut(&mut self) -> &mut [u8] {
     65         // SAFETY: len <= LEN
     66         unsafe { self.buf.get_unchecked_mut(..self.len as usize) }
     67     }
     68 }
     69 
     70 impl<const LEN: usize> AsRef<str> for InlineStr<LEN> {
     71     #[inline]
     72     fn as_ref(&self) -> &str {
     73         // SAFETY: len <= LEN && buf[..len] are all ASCII uppercase
     74         unsafe { std::str::from_utf8_unchecked(self.buf.get_unchecked(..self.len as usize)) }
     75     }
     76 }
     77 
     78 impl<const LEN: usize> Debug for InlineStr<LEN> {
     79     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     80         Debug::fmt(&self.as_ref(), f)
     81     }
     82 }
     83 
     84 impl<const LEN: usize> Deref for InlineStr<LEN> {
     85     type Target = [u8];
     86 
     87     #[inline]
     88     fn deref(&self) -> &Self::Target {
     89         // SAFETY: len <= LEN
     90         unsafe { self.buf.get_unchecked(..self.len as usize) }
     91     }
     92 }
     93 
     94 /** Convert a date to a UTC timestamp */
     95 pub fn date_to_utc_timestamp(date: &Date) -> Timestamp {
     96     date.to_zoned(TimeZone::UTC).unwrap().timestamp()
     97 }
     98 
     99 /** Get current timestamp truncated to micros precision */
    100 pub fn now_sql_stable_timestamp() -> Timestamp {
    101     Timestamp::from_microsecond(Timestamp::now().as_microsecond()).unwrap()
    102 }