Compare commits
No commits in common. "d1b6d153d4ed57b0ff9a3df1f4f5ac76c6119d06" and "2a4ed51824f6fc29d00c42320748c382e25cc780" have entirely different histories.
d1b6d153d4
...
2a4ed51824
11
mainbot.js
11
mainbot.js
@ -3,7 +3,7 @@
|
|||||||
const dialog = {
|
const dialog = {
|
||||||
commands: {
|
commands: {
|
||||||
start: {
|
start: {
|
||||||
buttons: start_buttons, // default is `null`
|
buttons: "start_buttons", // default is `null`
|
||||||
state: "start"
|
state: "start"
|
||||||
},
|
},
|
||||||
cancel: {
|
cancel: {
|
||||||
@ -20,17 +20,14 @@ const dialog = {
|
|||||||
stateful_msg_handlers: {
|
stateful_msg_handlers: {
|
||||||
start: {}, // everything is by default, so just send message `start`
|
start: {}, // everything is by default, so just send message `start`
|
||||||
enter_name: {
|
enter_name: {
|
||||||
// name of the handler function. This field has a side effect:
|
handler: "enter_name", // name of the handler function. This field has a
|
||||||
// when is set, no automatic sending of message, should be sent
|
// side effect: when is set, no automatic sending
|
||||||
// manually in handler
|
// of message, should be sent manually in handler
|
||||||
handler: enter_name,
|
|
||||||
state: "none"
|
state: "none"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
function enter_name() {}
|
|
||||||
|
|
||||||
const fmt = (number) => number.toString().padStart(2, '0');
|
const fmt = (number) => number.toString().padStart(2, '0');
|
||||||
|
|
||||||
const formatDate = (date) => {
|
const formatDate = (date) => {
|
||||||
|
|||||||
228
src/botscript.rs
228
src/botscript.rs
@ -1,10 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::utils::parcelable::{ParcelType, Parcelable, ParcelableError, ParcelableResult};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use quickjs_rusty::serde::from_js;
|
use quickjs_rusty::serde::from_js;
|
||||||
use quickjs_rusty::utils::create_empty_object;
|
use quickjs_rusty::utils::create_null;
|
||||||
use quickjs_rusty::utils::create_string;
|
|
||||||
use quickjs_rusty::Context;
|
use quickjs_rusty::Context;
|
||||||
use quickjs_rusty::ContextError;
|
use quickjs_rusty::ContextError;
|
||||||
use quickjs_rusty::ExecutionError;
|
use quickjs_rusty::ExecutionError;
|
||||||
@ -24,99 +22,18 @@ pub enum ScriptError {
|
|||||||
SerdeError(#[from] quickjs_rusty::serde::Error),
|
SerdeError(#[from] quickjs_rusty::serde::Error),
|
||||||
#[error("error value: {0:?}")]
|
#[error("error value: {0:?}")]
|
||||||
ValueError(#[from] ValueError),
|
ValueError(#[from] ValueError),
|
||||||
#[error("error bot function execution: {0:?}")]
|
|
||||||
BotFunctionError(String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ScriptResult<T> = Result<T, ScriptError>;
|
pub type ScriptResult<T> = Result<T, ScriptError>;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct BotFunction {
|
pub struct BotFunction(String); // temporal workaround
|
||||||
func: FunctionMarker,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum FunctionMarker {
|
|
||||||
/// serde is not able to (de)serialize this, so ignore it and fill
|
|
||||||
/// in runtime with injection in DeserializeJS
|
|
||||||
#[serde(skip)]
|
|
||||||
Function(JsFunction),
|
|
||||||
StrTemplate(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FunctionMarker {
|
|
||||||
pub fn as_str_template(&self) -> Option<&String> {
|
|
||||||
if let Self::StrTemplate(v) = self {
|
|
||||||
Some(v)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_function(&self) -> Option<&JsFunction> {
|
|
||||||
if let Self::Function(v) = self {
|
|
||||||
Some(v)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_js_function(&mut self, f: JsFunction) {
|
|
||||||
*self = Self::Function(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parcelable<Self> for BotFunction {
|
|
||||||
fn get_field(
|
|
||||||
&mut self,
|
|
||||||
_name: &str,
|
|
||||||
) -> crate::utils::parcelable::ParcelableResult<ParcelType<Self>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve(&mut self) -> ParcelableResult<ParcelType<Self>>
|
|
||||||
where
|
|
||||||
Self: Sized + 'static,
|
|
||||||
{
|
|
||||||
Ok(ParcelType::Function(self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BotFunction {
|
impl BotFunction {
|
||||||
pub fn by_name(name: String) -> Self {
|
|
||||||
Self {
|
|
||||||
func: FunctionMarker::StrTemplate(name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call_context(&self, runner: &Runner) -> ScriptResult<JsValue> {
|
pub fn call_context(&self, runner: &Runner) -> ScriptResult<JsValue> {
|
||||||
match &self.func {
|
let func_name = &self.0;
|
||||||
FunctionMarker::Function(f) => {
|
|
||||||
let val = f.call(Default::default())?;
|
|
||||||
Ok(val)
|
|
||||||
}
|
|
||||||
FunctionMarker::StrTemplate(func_name) => runner.run_script(&format!("{func_name}()")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call(&self) -> ScriptResult<JsValue> {
|
runner.run_script(&format!("{func_name}()"))
|
||||||
self.call_args(Default::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call_args(&self, args: Vec<JsValue>) -> ScriptResult<JsValue> {
|
|
||||||
if let FunctionMarker::Function(f) = &self.func {
|
|
||||||
let val = f.call(args)?;
|
|
||||||
Ok(val)
|
|
||||||
} else {
|
|
||||||
Err(ScriptError::BotFunctionError(
|
|
||||||
"Js Function is not defined".to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_js_function(&mut self, f: JsFunction) {
|
|
||||||
self.func.set_js_function(f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,28 +61,14 @@ impl DeserializerJS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize_js<'a, T: Deserialize<'a> + Parcelable<BotFunction> + 'static>(
|
pub fn deserialize_js<'a, T: Deserialize<'a>>(value: &'a JsValue) -> ScriptResult<T> {
|
||||||
value: &'a JsValue,
|
|
||||||
) -> ScriptResult<T> {
|
|
||||||
let mut s = Self::new();
|
let mut s = Self::new();
|
||||||
|
|
||||||
s.inject_templates(value, "".to_string())?;
|
s.inject_templates(value, "".to_string())?;
|
||||||
|
|
||||||
let mut res = value.js_into()?;
|
let res = value.js_into()?;
|
||||||
|
|
||||||
for (k, jsf) in s.fn_map {
|
// val.map_functions(s.fn_map);
|
||||||
let item: ParcelType<'_, BotFunction> =
|
|
||||||
match Parcelable::<BotFunction>::get_nested(&mut res, &k) {
|
|
||||||
Ok(item) => item,
|
|
||||||
Err(err) => {
|
|
||||||
log::error!("Failed to inject original functions to structs, error: {err}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if let ParcelType::Function(f) = item {
|
|
||||||
f.set_js_function(jsf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
@ -199,24 +102,7 @@ impl DeserializerJS {
|
|||||||
Err(err) => return Err(ScriptError::ValueError(err)),
|
Err(err) => return Err(ScriptError::ValueError(err)),
|
||||||
};
|
};
|
||||||
let res = match self.inject_templates(&p, path.clone() + &k)? {
|
let res = match self.inject_templates(&p, path.clone() + &k)? {
|
||||||
Some(_) => {
|
Some(_) => o.set_property(&k, JsValue::new(o.context(), create_null())),
|
||||||
let fo = JsValue::new(
|
|
||||||
o.context(),
|
|
||||||
create_empty_object(o.context()).expect("couldn't create object"),
|
|
||||||
)
|
|
||||||
.try_into_object()
|
|
||||||
.expect("the object created was not an object :/");
|
|
||||||
fo.set_property(
|
|
||||||
"func",
|
|
||||||
JsValue::new(
|
|
||||||
o.context(),
|
|
||||||
create_string(o.context(), "somefunc")
|
|
||||||
.expect("couldn't create string"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.expect("wasn't able to set property on object :/");
|
|
||||||
o.set_property(&k, fo.into_value())
|
|
||||||
}
|
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
};
|
};
|
||||||
match res {
|
match res {
|
||||||
@ -255,21 +141,6 @@ pub enum KeyboardDefinition {
|
|||||||
Function(BotFunction),
|
Function(BotFunction),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parcelable<BotFunction> for KeyboardDefinition {
|
|
||||||
fn get_field(&mut self, _name: &str) -> ParcelableResult<ParcelType<BotFunction>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
fn resolve(&mut self) -> ParcelableResult<ParcelType<BotFunction>>
|
|
||||||
where
|
|
||||||
Self: Sized + 'static,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
KeyboardDefinition::Rows(rows) => Ok(rows.resolve()?),
|
|
||||||
KeyboardDefinition::Function(f) => Ok(f.resolve()?),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResolveValue for KeyboardDefinition {
|
impl ResolveValue for KeyboardDefinition {
|
||||||
type Value = Vec<<RowDefinition as ResolveValue>::Value>;
|
type Value = Vec<<RowDefinition as ResolveValue>::Value>;
|
||||||
|
|
||||||
@ -277,7 +148,7 @@ impl ResolveValue for KeyboardDefinition {
|
|||||||
match self {
|
match self {
|
||||||
KeyboardDefinition::Rows(rows) => rows.into_iter().map(|r| r.resolve(runner)).collect(),
|
KeyboardDefinition::Rows(rows) => rows.into_iter().map(|r| r.resolve(runner)).collect(),
|
||||||
KeyboardDefinition::Function(f) => {
|
KeyboardDefinition::Function(f) => {
|
||||||
<Self as ResolveValue>::resolve(f.call_context(runner)?.js_into()?, runner)
|
Self::resolve(f.call_context(runner)?.js_into()?, runner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,21 +161,6 @@ pub enum RowDefinition {
|
|||||||
Function(BotFunction),
|
Function(BotFunction),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parcelable<BotFunction> for RowDefinition {
|
|
||||||
fn get_field(&mut self, _name: &str) -> ParcelableResult<ParcelType<BotFunction>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
fn resolve(&mut self) -> ParcelableResult<ParcelType<BotFunction>>
|
|
||||||
where
|
|
||||||
Self: Sized + 'static,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
Self::Buttons(buttons) => Ok(buttons.resolve()?),
|
|
||||||
Self::Function(f) => Ok(f.resolve()?),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResolveValue for RowDefinition {
|
impl ResolveValue for RowDefinition {
|
||||||
type Value = Vec<<ButtonDefinition as ResolveValue>::Value>;
|
type Value = Vec<<ButtonDefinition as ResolveValue>::Value>;
|
||||||
|
|
||||||
@ -313,9 +169,7 @@ impl ResolveValue for RowDefinition {
|
|||||||
RowDefinition::Buttons(buttons) => {
|
RowDefinition::Buttons(buttons) => {
|
||||||
buttons.into_iter().map(|b| b.resolve(runner)).collect()
|
buttons.into_iter().map(|b| b.resolve(runner)).collect()
|
||||||
}
|
}
|
||||||
RowDefinition::Function(f) => {
|
RowDefinition::Function(f) => Self::resolve(f.call_context(runner)?.js_into()?, runner),
|
||||||
<Self as ResolveValue>::resolve(f.call_context(runner)?.js_into()?, runner)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -336,40 +190,18 @@ impl ResolveValue for ButtonDefinition {
|
|||||||
ButtonDefinition::Button(button) => Ok(button),
|
ButtonDefinition::Button(button) => Ok(button),
|
||||||
ButtonDefinition::ButtonLiteral(l) => Ok(ButtonRaw::from_literal(l)),
|
ButtonDefinition::ButtonLiteral(l) => Ok(ButtonRaw::from_literal(l)),
|
||||||
ButtonDefinition::Function(f) => {
|
ButtonDefinition::Function(f) => {
|
||||||
<Self as ResolveValue>::resolve(f.call_context(runner)?.js_into()?, runner)
|
Self::resolve(f.call_context(runner)?.js_into()?, runner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parcelable<BotFunction> for ButtonDefinition {
|
|
||||||
fn get_field(&mut self, _name: &str) -> ParcelableResult<ParcelType<BotFunction>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
fn resolve(&mut self) -> ParcelableResult<ParcelType<BotFunction>>
|
|
||||||
where
|
|
||||||
Self: Sized + 'static,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
Self::Button(braw) => Ok(braw.resolve()?),
|
|
||||||
Self::ButtonLiteral(s) => Ok(s.resolve()?),
|
|
||||||
Self::Function(f) => Ok(f.resolve()?),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct ButtonRaw {
|
pub struct ButtonRaw {
|
||||||
name: ButtonName,
|
name: ButtonName,
|
||||||
callback_name: String,
|
callback_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Parcelable<F> for ButtonRaw {
|
|
||||||
fn get_field(&mut self, _name: &str) -> ParcelableResult<ParcelType<F>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ButtonRaw {
|
impl ButtonRaw {
|
||||||
pub fn from_literal(literal: String) -> Self {
|
pub fn from_literal(literal: String) -> Self {
|
||||||
ButtonRaw {
|
ButtonRaw {
|
||||||
@ -402,54 +234,18 @@ pub struct BotMessage {
|
|||||||
handler: Option<BotFunction>,
|
handler: Option<BotFunction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parcelable<BotFunction> for BotMessage {
|
|
||||||
fn get_field(&mut self, name: &str) -> ParcelableResult<ParcelType<BotFunction>> {
|
|
||||||
match name {
|
|
||||||
"buttons" => Ok(self.buttons.resolve()?),
|
|
||||||
"state" => Ok(self.state.resolve()?),
|
|
||||||
"handler" => Ok(self.handler.resolve()?),
|
|
||||||
field => Err(ParcelableError::FieldError(format!(
|
|
||||||
"tried to get field {field}, but this field does not exists or private"
|
|
||||||
))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct BotDialog {
|
pub struct BotDialog {
|
||||||
pub commands: HashMap<String, BotMessage>,
|
pub commands: HashMap<String, BotMessage>,
|
||||||
stateful_msg_handlers: HashMap<String, BotMessage>,
|
stateful_msg_handlers: HashMap<String, BotMessage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parcelable<BotFunction> for BotDialog {
|
|
||||||
fn get_field(&mut self, name: &str) -> Result<ParcelType<BotFunction>, ParcelableError> {
|
|
||||||
match name {
|
|
||||||
"commands" => Ok(ParcelType::Parcelable(&mut self.commands)),
|
|
||||||
"stateful_msg_handlers" => Ok(ParcelType::Parcelable(&mut self.stateful_msg_handlers)),
|
|
||||||
field => Err(ParcelableError::FieldError(format!(
|
|
||||||
"tried to get field {field}, but this field does not exists or private"
|
|
||||||
))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct RunnerConfig {
|
pub struct RunnerConfig {
|
||||||
config: BotConfig,
|
config: BotConfig,
|
||||||
pub dialog: BotDialog,
|
pub dialog: BotDialog,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parcelable<BotFunction> for RunnerConfig {
|
|
||||||
fn get_field(&mut self, name: &str) -> Result<ParcelType<BotFunction>, ParcelableError> {
|
|
||||||
match name {
|
|
||||||
"dialog" => Ok(ParcelType::Parcelable(&mut self.dialog)),
|
|
||||||
field => Err(ParcelableError::FieldError(format!(
|
|
||||||
"tried to get field {field}, but this field does not exists or private"
|
|
||||||
))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Runner {
|
pub struct Runner {
|
||||||
context: Context,
|
context: Context,
|
||||||
}
|
}
|
||||||
@ -538,7 +334,7 @@ mod tests {
|
|||||||
.run_script("function cancel_buttons() {return 'cancelation'}")
|
.run_script("function cancel_buttons() {return 'cancelation'}")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let f = BotFunction::by_name("cancel_buttons".to_string());
|
let f = BotFunction("cancel_buttons".to_string());
|
||||||
let res = f.call_context(&runner).unwrap();
|
let res = f.call_context(&runner).unwrap();
|
||||||
|
|
||||||
println!("RES: {res:?}");
|
println!("RES: {res:?}");
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
pub mod parcelable;
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use teloxide::types::InlineKeyboardButton;
|
use teloxide::types::InlineKeyboardButton;
|
||||||
|
|
||||||
|
|||||||
@ -1,110 +0,0 @@
|
|||||||
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