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