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
34#[macro_export]
36macro_rules! object {
37 () => {
38 $crate::Value::Object(std::collections::HashMap::new())
39 };
40
41 ($($key:expr => $value:expr),+ $(,)?) => {
42 {
43 let mut map = std::collections::HashMap::new();
44 $(
45 map.insert($key.to_string(), $value.into());
46 )+
47 $crate::Value::Object(map)
48 }
49 };
50}
51
52#[macro_export]
54macro_rules! array {
55 () => {
56 $crate::Value::Array(Vec::new())
57 };
58
59 ($($value:expr),+ $(,)?) => {
60 {
61 let mut arr = Vec::new();
62 $(
63 arr.push($value.into());
64 )+
65 $crate::Value::Array(arr)
66 }
67 };
68}
69
70pub fn format_slug(name: &str) -> String {
72 name.to_lowercase().replace(' ', "-")
73}
74
75pub fn truncate_str(s: &str, max_len: usize) -> String {
77 if s.len() <= max_len { s.to_string() } else { format!("{}...", &s[..max_len]) }
78}
79
80pub fn hex_encode(bytes: &[u8]) -> String {
82 bytes.iter().map(|b| format!("{:02x}", b)).collect()
83}
84
85pub fn hex_decode(s: &str) -> Result<Vec<u8>, String> {
87 if !s.len().is_multiple_of(2) {
88 return Err("Invalid hex string length".to_string());
89 }
90 (0..s.len()).step_by(2).map(|i| u8::from_str_radix(&s[i..i + 2], 16).map_err(|e| e.to_string())).collect()
91}
92
93pub fn url_encode(s: &str) -> String {
95 s.chars()
96 .map(|c| if c.is_alphanumeric() || "-_.~".contains(c) { c.to_string() } else { format!("%{:02X}", c as u8) })
97 .collect()
98}
99
100pub fn url_decode(s: &str) -> Result<String, String> {
102 let mut result = String::new();
103 let mut chars = s.chars().peekable();
104 while let Some(c) = chars.next() {
105 if c == '%' {
106 let hex: String = chars.by_ref().take(2).collect();
107 let byte = u8::from_str_radix(&hex, 16).map_err(|e| e.to_string())?;
108 result.push(byte as char);
109 }
110 else if c == '+' {
111 result.push(' ');
112 }
113 else {
114 result.push(c);
115 }
116 }
117 Ok(result)
118}