1#![warn(missing_docs)]
2
3pub use rust_decimal::Decimal;
13pub use rust_decimal_macros::dec;
14
15mod error;
16mod value;
17
18pub use error::*;
19pub use value::*;
20
21#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
23pub struct BillingDimensions {
24 pub input_text: u64,
26 pub output_text: u64,
28 pub input_pixels: u64,
30 pub output_pixels: u64,
32}
33
34pub type DatabaseErrorKind = WaeErrorKind;
36
37#[macro_export]
39macro_rules! object {
40 () => {
41 $crate::Value::Object(std::collections::HashMap::new())
42 };
43
44 ($($key:expr => $value:expr),+ $(,)?) => {
45 {
46 let mut map = std::collections::HashMap::new();
47 $(
48 map.insert($key.to_string(), $value.into());
49 )+
50 $crate::Value::Object(map)
51 }
52 };
53}
54
55#[macro_export]
57macro_rules! array {
58 () => {
59 $crate::Value::Array(Vec::new())
60 };
61
62 ($($value:expr),+ $(,)?) => {
63 {
64 let mut arr = Vec::new();
65 $(
66 arr.push($value.into());
67 )+
68 $crate::Value::Array(arr)
69 }
70 };
71}
72
73pub fn format_slug(name: &str) -> String {
75 name.to_lowercase().replace(' ', "-")
76}
77
78pub fn truncate_str(s: &str, max_len: usize) -> String {
80 if s.len() <= max_len { s.to_string() } else { format!("{}...", &s[..max_len]) }
81}
82
83pub fn hex_encode(bytes: &[u8]) -> String {
85 bytes.iter().map(|b| format!("{:02x}", b)).collect()
86}
87
88pub fn hex_decode(s: &str) -> Result<Vec<u8>, String> {
90 if !s.len().is_multiple_of(2) {
91 return Err("Invalid hex string length".to_string());
92 }
93 (0..s.len()).step_by(2).map(|i| u8::from_str_radix(&s[i..i + 2], 16).map_err(|e| e.to_string())).collect()
94}
95
96pub fn url_encode(s: &str) -> String {
98 s.chars()
99 .map(|c| if c.is_alphanumeric() || "-_.~".contains(c) { c.to_string() } else { format!("%{:02X}", c as u8) })
100 .collect()
101}
102
103pub fn url_decode(s: &str) -> Result<String, String> {
105 let mut result = String::new();
106 let mut chars = s.chars().peekable();
107 while let Some(c) = chars.next() {
108 if c == '%' {
109 let hex: String = chars.by_ref().take(2).collect();
110 let byte = u8::from_str_radix(&hex, 16).map_err(|e| e.to_string())?;
111 result.push(byte as char);
112 }
113 else if c == '+' {
114 result.push(' ');
115 }
116 else {
117 result.push(c);
118 }
119 }
120 Ok(result)
121}