extern crate alloc;
use alloc::string::{String, ToString};
use core::str::FromStr;
use dataport::{PortCollectionAccessors, PortCollectionAccessorsCommon};
use tinyscript::{Environment, ScriptingValue};
use crate::{Error, databoard::Databoard};
impl Environment for Databoard {
fn define_env(&mut self, name: &str, value: impl Into<ScriptingValue>) -> Result<(), tinyscript::environment::Error> {
if self.contains_name(name) {
self.set_env(name, value)
} else {
let value = value.into();
match value {
ScriptingValue::Nil() => {
return Err(tinyscript::environment::Error::EnvVarUnknownType { name: name.into() });
}
ScriptingValue::Boolean(b) => match self.set(name, b) {
Ok(()) => {}
Err(cause) => {
return Err(tinyscript::environment::Error::EnvVarSet {
name: name.into(),
cause: cause.to_string().into(),
});
}
},
ScriptingValue::Float64(f) => match self.set(name, f) {
Ok(()) => {}
Err(cause) => {
return Err(tinyscript::environment::Error::EnvVarSet {
name: name.into(),
cause: cause.to_string().into(),
});
}
},
ScriptingValue::Int64(i) => match self.set(name, i) {
Ok(()) => {}
Err(cause) => {
return Err(tinyscript::environment::Error::EnvVarSet {
name: name.into(),
cause: cause.to_string().into(),
});
}
},
ScriptingValue::String(s) => match self.set_from_str(name, &s) {
Ok(()) => {}
Err(cause) => {
return Err(tinyscript::environment::Error::EnvVarSet {
name: name.into(),
cause: cause.to_string().into(),
});
}
},
}
Ok(())
}
}
#[allow(clippy::option_if_let_else)]
fn get_env(&self, name: &str) -> Result<ScriptingValue, tinyscript::environment::Error> {
self.entry(name).map_or_else(
|err| match err {
Error::Assignment { name: _, value } => i64::from_str(&value).map_or_else(
|_| {
f64::from_str(&value).map_or_else(
|_| {
bool::from_str(&value).map_or_else(
|_| Ok(ScriptingValue::String(value.to_string())),
|b| Ok(ScriptingValue::Boolean(b)),
)
},
|f| Ok(ScriptingValue::Float64(f)),
)
},
|i| Ok(ScriptingValue::Int64(i)),
),
_ => Err(tinyscript::environment::Error::EnvVarNotDefined { name: name.into() }),
},
|entry| {
if let Some(s) = entry.get::<String>().unwrap_or_default() {
Ok(ScriptingValue::String(s))
} else if let Some(b) = entry.get::<bool>().unwrap_or_default() {
Ok(ScriptingValue::Boolean(b))
} else if let Some(f) = entry.get::<f64>().unwrap_or_default() {
Ok(ScriptingValue::Float64(f))
} else if let Some(f) = entry.get::<f32>().unwrap_or_default() {
Ok(ScriptingValue::Float64(f64::from(f)))
} else if let Some(u) = entry.get::<u64>().unwrap_or_default() {
if u < i64::MAX as u64 {
#[allow(clippy::cast_possible_wrap)]
Ok(ScriptingValue::Int64(u as i64))
} else {
Err(tinyscript::environment::Error::EnvVarExceedsLimits { name: name.into() })
}
} else if let Some(i) = entry.get::<i64>().unwrap_or_default() {
Ok(ScriptingValue::Int64(i))
} else if let Some(u) = entry.get::<u32>().unwrap_or_default() {
Ok(ScriptingValue::Int64(i64::from(u)))
} else if let Some(i) = entry.get::<i32>().unwrap_or_default() {
Ok(ScriptingValue::Int64(i64::from(i)))
} else if let Some(u) = entry.get::<u16>().unwrap_or_default() {
Ok(ScriptingValue::Int64(i64::from(u)))
} else if let Some(i) = entry.get::<i16>().unwrap_or_default() {
Ok(ScriptingValue::Int64(i64::from(i)))
} else if let Some(u) = entry.get::<u8>().unwrap_or_default() {
Ok(ScriptingValue::Int64(i64::from(u)))
} else if let Some(i) = entry.get::<i8>().unwrap_or_default() {
Ok(ScriptingValue::Int64(i64::from(i)))
} else {
Err(tinyscript::environment::Error::EnvVarUnknownType { name: name.into() })
}
},
)
}
fn set_env(&mut self, name: &str, value: impl Into<ScriptingValue>) -> Result<(), tinyscript::environment::Error> {
if !self.contains_name(name) {
return Err(tinyscript::environment::Error::EnvVarNotDefined { name: name.into() });
}
let value = value.into();
match value {
ScriptingValue::Nil() => Err(tinyscript::environment::Error::EnvVarUnknownType { name: name.into() }),
ScriptingValue::Boolean(b) => match self.set::<bool>(name, b) {
Ok(()) => Ok(()),
Err(err) => Err(tinyscript::environment::Error::EnvVarSet {
name: name.into(),
cause: err.to_string().into(),
}),
},
ScriptingValue::Float64(f) => match self.set::<f64>(name, f) {
Ok(()) => Ok(()),
Err(_) => {
if f < f64::from(f32::MAX) {
#[allow(clippy::cast_possible_truncation)]
match self.set::<f32>(name, f as f32) {
Ok(()) => Ok(()),
Err(_err) => {
let str_val = f.to_string();
if self.set_from_str(name, &str_val).is_ok() {
Ok(())
} else {
Err(tinyscript::environment::Error::EnvVarWrongType { name: name.into() })
}
}
}
} else {
Err(tinyscript::environment::Error::EnvVarExceedsLimits { name: name.into() })
}
}
},
ScriptingValue::Int64(i_raw) => {
if self.set::<i64>(name, i_raw).is_ok() {
Ok(())
} else if let Ok(i) = i32::try_from(i_raw)
&& self.set::<i32>(name, i).is_ok()
{
Ok(())
} else if let Ok(i) = i16::try_from(i_raw)
&& self.set::<i16>(name, i).is_ok()
{
Ok(())
} else if let Ok(i) = i8::try_from(i_raw)
&& self.set::<i8>(name, i).is_ok()
{
Ok(())
} else if i_raw > 0 {
if let Ok(i) = u64::try_from(i_raw)
&& self.set::<u64>(name, i).is_ok()
{
Ok(())
} else if let Ok(i) = u32::try_from(i_raw)
&& self.set::<u32>(name, i).is_ok()
{
Ok(())
} else if let Ok(i) = u16::try_from(i_raw)
&& self.set::<u16>(name, i).is_ok()
{
Ok(())
} else if let Ok(i) = u8::try_from(i_raw)
&& self.set::<u8>(name, i).is_ok()
{
Ok(())
} else {
let str_val = i_raw.to_string();
if self.set_from_str(name, &str_val).is_ok() {
Ok(())
} else {
Err(tinyscript::environment::Error::EnvVarWrongType { name: name.into() })
}
}
} else {
let str_val = i_raw.to_string();
if self.set_from_str(name, &str_val).is_ok() {
Ok(())
} else {
Err(tinyscript::environment::Error::EnvVarWrongType { name: name.into() })
}
}
}
ScriptingValue::String(s) => match self.set_from_str(name, &s) {
Ok(()) => Ok(()),
Err(_) => match self.set(name, s) {
Ok(()) => Ok(()),
Err(err) => Err(tinyscript::environment::Error::EnvVarSet {
name: name.into(),
cause: err.to_string().into(),
}),
},
},
}
}
}