use std::num::NonZero; #[derive(Clone, Debug)] pub enum Parameter { Indexed(NonZero), Named(String, NonZero), } impl PartialEq for Parameter { fn eq(&self, other: &Self) -> bool { self.index() == other.index() } } impl Parameter { pub fn index(&self) -> NonZero { match self { Parameter::Indexed(index) => *index, Parameter::Named(_, index) => *index, } } } #[derive(Debug)] pub struct Parameters { next_index: NonZero, pub list: Vec, } impl Default for Parameters { fn default() -> Self { Self::new() } } impl Parameters { pub fn new() -> Self { Self { next_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) -> Option { self.list.iter().find_map(|p| match p { 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) -> Option> { 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 { let index = self.next_index; self.next_index = self.next_index.checked_add(1).unwrap(); index } pub fn push(&mut self, name: impl AsRef) -> NonZero { match name.as_ref() { 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()); tracing::trace!("named parameter at {index} as {name}"); index } None => { let index = self.next_index(); self.list.push(Parameter::Named(name.to_owned(), index)); tracing::trace!("named parameter at {index} as {name}"); index } } } index => { // SAFETY: Guaranteed from parser that the index is bigger than 0. let index: NonZero = index.parse().unwrap(); if index >= self.next_index { self.next_index = index.checked_add(1).unwrap(); } self.list.push(Parameter::Indexed(index)); tracing::trace!("indexed parameter at {index}"); index } } } }