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 }