http_path_params/path_params/
mod.rs1use alloc::string::String;
2
3use downcast_rs::{impl_downcast, DowncastSync};
4use dyn_clone::{clone_trait_object, DynClone};
5
6use crate::PathParamsInfo;
7
8mod impl_id;
9mod impl_internal;
10mod impl_path_param;
11mod impl_username;
12
13pub trait PathParams: DowncastSync + DynClone {
15 fn size(&self) -> usize;
16
17 fn get(&self, _index: usize) -> (Option<&str>, String);
18 fn set(
19 &mut self,
20 _index: usize,
21 _name_and_value: &(Option<&str>, &str),
22 ) -> Result<(), SetError>;
23 fn verify(&self, _index: usize, _name_and_value: &(Option<&str>, &str))
24 -> Result<(), SetError>;
25
26 fn info(&self) -> PathParamsInfo {
27 PathParamsInfo(
28 (0..self.size())
29 .map(|i| {
30 let (name, value) = self.get(i);
31 (name.map(Into::into), value)
32 })
33 .collect(),
34 )
35 }
36 fn set_from_info(&mut self, info: &PathParamsInfo) -> Result<(), SetError> {
37 if info.0.len() != self.size() {
38 return Err(SetError::InfoLengthMismatch);
39 }
40 (0..self.size()).try_for_each(|i| {
41 let (name, value) = info.get(i).expect("unreachable");
42 self.set(i, &(name.as_deref(), value.as_ref()))
43 })
44 }
45}
46
47impl_downcast!(PathParams);
48clone_trait_object!(PathParams);
49
50impl core::fmt::Debug for dyn PathParams {
51 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
52 f.debug_tuple("PathParams").field(&self.info()).finish()
53 }
54}
55impl core::fmt::Debug for dyn PathParams + Send {
56 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
57 f.debug_tuple("PathParams").field(&self.info()).finish()
58 }
59}
60impl core::fmt::Debug for dyn PathParams + Send + Sync {
61 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
62 f.debug_tuple("PathParams").field(&self.info()).finish()
63 }
64}
65
66#[derive(Debug, Clone)]
68pub enum SetError {
69 InfoLengthMismatch,
70 ValueParseFailed(String),
71}
72impl core::fmt::Display for SetError {
73 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74 write!(f, "{self:?}")
75 }
76}
77#[cfg(feature = "std")]
78impl std::error::Error for SetError {}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 use alloc::{boxed::Box, string::ToString as _, vec, vec::Vec};
85
86 #[derive(Debug, Clone)]
87 struct PathParamsStorage(Vec<Box<dyn PathParams>>);
88
89 #[test]
90 fn test_path_params_dyn_clone_and_debug() {
91 let path_params_list = PathParamsStorage(vec![Box::new(1), Box::new("foo".to_string())]);
92 #[allow(clippy::redundant_clone)]
93 let path_params_list = path_params_list.clone();
94 #[cfg(feature = "std")]
95 println!("path_params_list: {path_params_list:?}");
96 assert_eq!(path_params_list.0.len(), 2);
97 }
98
99 #[test]
100 fn test_path_params_downcast() {
101 let path_params: Box<dyn PathParams> = Box::new("foo".to_string());
102 assert_eq!(path_params.downcast_ref::<String>().unwrap(), "foo");
103 }
104
105 #[cfg(feature = "std")]
106 #[test]
107 fn test_set_error_impl_std_error() {
108 use crate::PathParam;
109
110 fn doing() -> Result<(), Box<dyn std::error::Error>> {
111 let mut path_params = (PathParam(1_usize), PathParam("foo".to_string()));
112 path_params.set(0, &(None, "bar"))?;
113 Ok(())
114 }
115 assert!(doing().is_err());
116 }
117}