use alloc::{string::String, vec::Vec};
use core::fmt::{self, Debug, Display};
use downcast_rs::{impl_downcast, DowncastSync};
use dyn_clone::{clone_trait_object, DynClone};
mod impl_internal;
mod impl_path_param;
pub trait PathParams: DowncastSync + DynClone {
fn size(&self) -> usize;
fn value(&self, _index: usize) -> String;
fn set_value(&mut self, _index: usize, _value: &str) -> Result<(), ValueSetError>;
fn name(&self, _index: usize) -> Option<&str> {
None
}
fn values(&self) -> Vec<String> {
(0..self.size())
.into_iter()
.map(|i| self.value(i))
.collect()
}
fn set_values(&mut self, values: &[String]) -> Result<(), ValueSetError> {
if values.len() != self.size() {
return Err(ValueSetError::SizeMismatch);
}
(0..self.size())
.into_iter()
.try_for_each(|i| self.set_value(i, values.get(i).expect("unreachable")))
}
}
impl_downcast!(PathParams);
clone_trait_object!(PathParams);
impl Debug for (dyn PathParams) {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "PathParams{{values: {:?}}}", self.values())
}
}
impl Debug for (dyn PathParams + Send + Sync) {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "PathParams{{values: {:?}}}", self.values())
}
}
#[derive(Debug, Clone)]
pub enum ValueSetError {
SizeMismatch,
ParseFailed(String),
}
impl Display for ValueSetError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
#[cfg(feature = "std")]
impl std::error::Error for ValueSetError {}
#[cfg(test)]
mod tests {
use super::*;
use alloc::{boxed::Box, string::ToString as _, vec};
#[derive(Debug, Clone)]
struct PathParamsStorage(Vec<Box<dyn PathParams>>);
#[test]
fn test_path_params_dyn_clone_and_debug() {
let path_params_list = PathParamsStorage(vec![Box::new(1), Box::new("foo".to_string())]);
#[allow(clippy::redundant_clone)]
let path_params_list = path_params_list.clone();
#[cfg(feature = "std")]
println!("path_params_list: {:?}", path_params_list);
assert_eq!(path_params_list.0.len(), 2);
}
#[test]
fn test_path_params_downcast() {
let path_params: Box<dyn PathParams> = Box::new("foo".to_string());
assert_eq!(path_params.downcast_ref::<String>().unwrap(), "foo");
}
#[cfg(feature = "std")]
#[test]
fn test_value_set_error_impl_std_error() {
use crate::PathParam;
fn doing() -> Result<(), Box<dyn std::error::Error>> {
let mut path_params = (PathParam(1_usize), PathParam("foo".to_string()));
path_params.set_value(0, "bar")?;
Ok(())
}
assert!(doing().is_err());
}
}