create Parcelable trait with default implementations
This commit is contained in:
parent
2a4ed51824
commit
d5f39e4e60
@ -1,3 +1,5 @@
|
|||||||
|
pub mod parcelable;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use teloxide::types::InlineKeyboardButton;
|
use teloxide::types::InlineKeyboardButton;
|
||||||
|
|
||||||
|
|||||||
110
src/utils/parcelable.rs
Normal file
110
src/utils/parcelable.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub enum ParcelType<'a, F> {
|
||||||
|
Function(&'a mut F),
|
||||||
|
Parcelable(&'a mut dyn Parcelable<F>),
|
||||||
|
Other(()),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum ParcelableError {
|
||||||
|
#[error("error to get field: {0:?}")]
|
||||||
|
FieldError(String),
|
||||||
|
#[error("error when addressing nested element: {0:?}")]
|
||||||
|
NestError(String),
|
||||||
|
#[error("error to resolve Parcelable: {0:?}")]
|
||||||
|
ResolveError(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ParcelableResult<T> = Result<T, ParcelableError>;
|
||||||
|
|
||||||
|
pub trait Parcelable<F> {
|
||||||
|
fn get_field(&mut self, name: &str) -> ParcelableResult<ParcelType<F>>;
|
||||||
|
|
||||||
|
fn resolve(&mut self) -> ParcelableResult<ParcelType<F>>
|
||||||
|
where
|
||||||
|
Self: Sized + 'static,
|
||||||
|
{
|
||||||
|
let root = ParcelableResult::Ok(ParcelType::Parcelable(self));
|
||||||
|
root
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get nested field by name, which is fields joined by dot
|
||||||
|
/// for example: passing name "field1.somefield" will be the same
|
||||||
|
/// as using `struct.field1.somefield`, by dynamically
|
||||||
|
fn get_nested(&mut self, name: &str) -> ParcelableResult<ParcelType<F>>
|
||||||
|
where
|
||||||
|
Self: Sized + 'static,
|
||||||
|
{
|
||||||
|
let root = ParcelableResult::Ok(ParcelType::Parcelable(self));
|
||||||
|
name.split('.')
|
||||||
|
.fold(root, |s: ParcelableResult<ParcelType<F>>, field| match s? {
|
||||||
|
ParcelType::Parcelable(p) => p.get_field(field),
|
||||||
|
_ => Err(ParcelableError::NestError(format!(
|
||||||
|
"Failed to get field {field}. End of nestment"
|
||||||
|
))),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F> Parcelable<F> for String {
|
||||||
|
fn get_field(&mut self, _name: &str) -> ParcelableResult<ParcelType<F>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve(&mut self) -> ParcelableResult<ParcelType<F>>
|
||||||
|
where
|
||||||
|
Self: Sized + 'static,
|
||||||
|
{
|
||||||
|
Ok(ParcelType::Other(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T: Parcelable<F>> Parcelable<F> for Option<T> {
|
||||||
|
fn get_field(&mut self, name: &str) -> ParcelableResult<ParcelType<F>> {
|
||||||
|
Err(ParcelableError::FieldError(format!(
|
||||||
|
"tried to get field {name}, but calls of get_field are not allowed on Option"
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve(&mut self) -> crate::utils::parcelable::ParcelableResult<ParcelType<F>>
|
||||||
|
where
|
||||||
|
Self: Sized + 'static,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Some(v) => Ok(v.resolve()?),
|
||||||
|
None => Err(ParcelableError::ResolveError("Option was None".to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, V: Parcelable<F> + 'static> Parcelable<F> for HashMap<String, V> {
|
||||||
|
fn get_field(&mut self, name: &str) -> ParcelableResult<ParcelType<F>> {
|
||||||
|
match self.get_mut(name) {
|
||||||
|
Some(v) => Ok(Parcelable::resolve(v)?),
|
||||||
|
None => Err(ParcelableError::FieldError(format!(
|
||||||
|
"tried to get value by key {name}, but this key does not exists"
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T: Parcelable<F> + 'static> Parcelable<F> for Vec<T> {
|
||||||
|
fn get_field(&mut self, name: &str) -> ParcelableResult<ParcelType<F>> {
|
||||||
|
let index: usize = match name.parse() {
|
||||||
|
Ok(index) => index,
|
||||||
|
Err(err) => {
|
||||||
|
return Err(ParcelableError::FieldError(format!(
|
||||||
|
"Failed to parse field name `{name}` as an array index, err: {err}"
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let veclen = self.len();
|
||||||
|
let value = match self.get_mut(index) {
|
||||||
|
Some(value) => value,
|
||||||
|
None => return Err(ParcelableError::FieldError(format!("Failed to get vec element with index {index}, probably out of bound (vec len: {veclen})"))),
|
||||||
|
};
|
||||||
|
|
||||||
|
Parcelable::resolve(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user