forked from tursodatabase/limbo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparameters.rs
117 lines (106 loc) · 3.4 KB
/
parameters.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::num::NonZero;
#[derive(Clone, Debug)]
pub enum Parameter {
Anonymous(NonZero<usize>),
Indexed(NonZero<usize>),
Named(String, NonZero<usize>),
}
impl PartialEq for Parameter {
fn eq(&self, other: &Self) -> bool {
self.index() == other.index()
}
}
impl Parameter {
pub fn index(&self) -> NonZero<usize> {
match self {
Parameter::Anonymous(index) => *index,
Parameter::Indexed(index) => *index,
Parameter::Named(_, index) => *index,
}
}
}
#[derive(Debug)]
pub struct Parameters {
index: NonZero<usize>,
pub list: Vec<Parameter>,
}
impl Default for Parameters {
fn default() -> Self {
Self::new()
}
}
impl Parameters {
pub fn new() -> Self {
Self {
index: 1.try_into().unwrap(),
list: vec![],
}
}
pub fn count(&self) -> usize {
let mut params = self.list.clone();
params.dedup();
params.len()
}
pub fn name(&self, index: NonZero<usize>) -> Option<String> {
self.list.iter().find_map(|p| match p {
Parameter::Anonymous(i) if *i == index => Some("?".to_string()),
Parameter::Indexed(i) if *i == index => Some(format!("?{i}")),
Parameter::Named(name, i) if *i == index => Some(name.to_owned()),
_ => None,
})
}
pub fn index(&self, name: impl AsRef<str>) -> Option<NonZero<usize>> {
self.list
.iter()
.find_map(|p| match p {
Parameter::Named(n, index) if n == name.as_ref() => Some(index),
_ => None,
})
.copied()
}
pub fn next_index(&mut self) -> NonZero<usize> {
let index = self.index;
self.index = self.index.checked_add(1).unwrap();
index
}
pub fn push(&mut self, name: impl AsRef<str>) -> NonZero<usize> {
match name.as_ref() {
"" => {
let index = self.next_index();
self.list.push(Parameter::Anonymous(index));
log::trace!("anonymous parameter at {index}");
index
}
name if name.starts_with(['$', ':', '@', '#']) => {
match self
.list
.iter()
.find(|p| matches!(p, Parameter::Named(n, _) if name == n))
{
Some(t) => {
let index = t.index();
self.list.push(t.clone());
log::trace!("named parameter at {index} as {name}");
index
}
None => {
let index = self.next_index();
self.list.push(Parameter::Named(name.to_owned(), index));
log::trace!("named parameter at {index} as {name}");
index
}
}
}
index => {
// SAFETY: Guaranteed from parser that the index is bigger than 0.
let index: NonZero<usize> = index.parse().unwrap();
if index > self.index {
self.index = index.checked_add(1).unwrap();
}
self.list.push(Parameter::Indexed(index));
log::trace!("indexed parameter at {index}");
index
}
}
}
}