1use crate::valuer::SqlValuer;
7use std::marker::PhantomData;
8
9#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
11pub enum ScanError {
12 #[error("builder not enough tokens")]
13 NotEnoughTokens,
14 #[error("builder failed to parse int: {0}")]
15 ParseInt(#[from] std::num::ParseIntError),
16 #[error("builder failed to parse float")]
17 ParseFloat,
18 #[error("builder failed to parse bool")]
19 ParseBool,
20 #[error("builder scan into Option<T> is not supported")]
21 UnsupportedOption,
22 #[error("builder scan into this type is not supported")]
23 UnsupportedType,
24}
25
26pub trait ScanFromStr {
28 fn scan_from_str(&mut self, s: &str) -> Result<(), ScanError>;
29}
30
31impl ScanFromStr for String {
32 fn scan_from_str(&mut self, s: &str) -> Result<(), ScanError> {
33 self.clear();
34 self.push_str(s);
35 Ok(())
36 }
37}
38
39impl ScanFromStr for i64 {
40 fn scan_from_str(&mut self, s: &str) -> Result<(), ScanError> {
41 *self = s.parse::<i64>()?;
42 Ok(())
43 }
44}
45
46impl ScanFromStr for i32 {
47 fn scan_from_str(&mut self, s: &str) -> Result<(), ScanError> {
48 *self = s.parse::<i32>()?;
49 Ok(())
50 }
51}
52
53impl ScanFromStr for u64 {
54 fn scan_from_str(&mut self, s: &str) -> Result<(), ScanError> {
55 *self = s.parse::<u64>()?;
56 Ok(())
57 }
58}
59
60impl ScanFromStr for u16 {
61 fn scan_from_str(&mut self, s: &str) -> Result<(), ScanError> {
62 *self = s.parse::<u16>()?;
63 Ok(())
64 }
65}
66
67impl ScanFromStr for f64 {
68 fn scan_from_str(&mut self, s: &str) -> Result<(), ScanError> {
69 *self = s.parse::<f64>().map_err(|_| ScanError::ParseFloat)?;
70 Ok(())
71 }
72}
73
74impl ScanFromStr for bool {
75 fn scan_from_str(&mut self, s: &str) -> Result<(), ScanError> {
76 match s {
77 "true" | "TRUE" | "1" => {
78 *self = true;
79 Ok(())
80 }
81 "false" | "FALSE" | "0" => {
82 *self = false;
83 Ok(())
84 }
85 _ => Err(ScanError::ParseBool),
86 }
87 }
88}
89
90impl<T: ScanFromStr> ScanFromStr for Option<T> {
91 fn scan_from_str(&mut self, s: &str) -> Result<(), ScanError> {
92 if s.eq_ignore_ascii_case("null") {
93 *self = None;
94 return Ok(());
95 }
96 let _ = s;
97 Err(ScanError::UnsupportedOption)
98 }
99}
100
101impl ScanFromStr for Box<dyn SqlValuer> {
102 fn scan_from_str(&mut self, _s: &str) -> Result<(), ScanError> {
103 Err(ScanError::UnsupportedType)
104 }
105}
106
107type Setter = fn(*mut (), &str) -> Result<(), ScanError>;
108
109fn set_impl<T: ScanFromStr>(ptr: *mut (), s: &str) -> Result<(), ScanError> {
110 let r = unsafe { &mut *(ptr as *mut T) };
112 r.scan_from_str(s)
113}
114
115#[derive(Debug)]
117pub struct ScanCell<'a> {
118 ptr: *mut (),
119 set: Setter,
120 _pd: PhantomData<&'a mut ()>,
121}
122
123impl<'a> ScanCell<'a> {
124 pub fn from_ptr<T: ScanFromStr>(ptr: *mut T) -> Self {
125 Self {
126 ptr: ptr as *mut (),
127 set: set_impl::<T>,
128 _pd: PhantomData,
129 }
130 }
131
132 pub fn set_from_str(&mut self, s: &str) -> Result<(), ScanError> {
133 (self.set)(self.ptr, s)
134 }
135}
136
137pub fn scan_tokens(input: &str, mut dests: Vec<ScanCell<'_>>) -> Result<(), ScanError> {
139 let mut it = input.split_whitespace();
140 for d in dests.iter_mut() {
141 let token = it.next().ok_or(ScanError::NotEnoughTokens)?;
142 d.set_from_str(token)?;
143 }
144 Ok(())
145}