use crate::error::Error;
use crate::helpers::Ignore;
use minicbor::bytes::ByteSlice;
use oc_wasm_futures::invoke::{component_method, Buffer};
use oc_wasm_helpers::{error::NullAndStringOr, Lockable};
use oc_wasm_safe::{
component::{Invoker, MethodCallError},
extref, Address,
};
pub const TYPE: &str = "eeprom";
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Eeprom(Address);
impl Eeprom {
#[must_use = "This function is only useful for its return value"]
pub fn new(address: Address) -> Self {
Self(address)
}
#[must_use = "This function is only useful for its return value"]
pub fn address(&self) -> &Address {
&self.0
}
}
impl<'invoker, 'buffer, B: 'buffer + Buffer> Lockable<'invoker, 'buffer, B> for Eeprom {
type Locked = Locked<'invoker, 'buffer, B>;
fn lock(&self, invoker: &'invoker mut Invoker, buffer: &'buffer mut B) -> Self::Locked {
Locked {
address: self.0,
invoker,
buffer,
}
}
}
pub struct Locked<'invoker, 'buffer, B: Buffer> {
address: Address,
invoker: &'invoker mut Invoker,
buffer: &'buffer mut B,
}
impl<'invoker, 'buffer, B: Buffer> Locked<'invoker, 'buffer, B> {
pub async fn get(self) -> Result<&'buffer [u8], Error> {
let ret: (&ByteSlice,) =
component_method::<(), _, _>(self.invoker, self.buffer, &self.address, "get", None)
.await?;
Ok(ret.0)
}
pub async fn set(&mut self, data: &[u8]) -> Result<(), Error> {
let data = unsafe { extref::Bytes::new(data) };
Self::map_errors::<Ignore>(
component_method(
self.invoker,
self.buffer,
&self.address,
"set",
Some(&(data,)),
)
.await,
Error::DataTooLarge,
)?;
Ok(())
}
pub async fn get_label(self) -> Result<&'buffer str, Error> {
let ret: (&'buffer str,) = component_method::<(), _, _>(
self.invoker,
self.buffer,
&self.address,
"getLabel",
None,
)
.await?;
Ok(ret.0)
}
pub async fn set_label(self, label: &str) -> Result<&'buffer str, Error> {
let label = unsafe { extref::String::new(label) };
let ret: (&'buffer str,) = Self::map_errors(
component_method(
self.invoker,
self.buffer,
&self.address,
"setLabel",
Some(&(label,)),
)
.await,
Error::BadComponent(oc_wasm_safe::error::Error::Unknown),
)?;
Ok(ret.0)
}
pub async fn get_size(&mut self) -> Result<usize, Error> {
let ret: (usize,) =
component_method::<(), _, _>(self.invoker, self.buffer, &self.address, "getSize", None)
.await?;
Ok(ret.0)
}
pub async fn get_checksum(&mut self) -> Result<u32, Error> {
let ret: (&'_ str,) = component_method::<(), _, _>(
self.invoker,
self.buffer,
&self.address,
"getChecksum",
None,
)
.await?;
let ret = ret.0;
if let Ok(ret) = u32::from_str_radix(ret, 16) {
Ok(ret)
} else {
Err(Error::BadComponent(oc_wasm_safe::error::Error::Unknown))
}
}
pub async fn make_read_only(&mut self, checksum: u32) -> Result<(), Error> {
let checksum = alloc::format!("{checksum:08x}");
let checksum = unsafe { extref::String::new(&checksum) };
Self::map_errors::<Ignore>(
component_method(
self.invoker,
self.buffer,
&self.address,
"makeReadonly",
Some(&(checksum,)),
)
.await,
Error::BadComponent(oc_wasm_safe::error::Error::Unknown),
)?;
Ok(())
}
pub async fn get_data_size(&mut self) -> Result<usize, Error> {
let ret: (usize,) = component_method::<(), _, _>(
self.invoker,
self.buffer,
&self.address,
"getDataSize",
None,
)
.await?;
Ok(ret.0)
}
pub async fn get_data(self) -> Result<&'buffer [u8], Error> {
let ret: (&ByteSlice,) =
component_method::<(), _, _>(self.invoker, self.buffer, &self.address, "getData", None)
.await?;
Ok(ret.0)
}
pub async fn set_data(&mut self, data: &[u8]) -> Result<(), Error> {
let data = unsafe { extref::Bytes::new(data) };
Self::map_errors::<Ignore>(
component_method(
self.invoker,
self.buffer,
&self.address,
"setData",
Some(&(data,)),
)
.await,
Error::DataTooLarge,
)?;
Ok(())
}
fn map_errors<T>(
x: Result<NullAndStringOr<'_, T>, MethodCallError<'_>>,
bad_parameters: Error,
) -> Result<T, Error> {
match x {
Ok(NullAndStringOr::Ok(x)) => Ok(x),
Ok(NullAndStringOr::Err("incorrect checksum")) => Err(Error::ChecksumMismatch),
Ok(NullAndStringOr::Err("not enough energy")) => Err(Error::NotEnoughEnergy),
Ok(NullAndStringOr::Err("storage is readonly")) => Err(Error::StorageReadOnly),
Ok(NullAndStringOr::Err(_)) => {
Err(Error::BadComponent(oc_wasm_safe::error::Error::Unknown))
}
Err(MethodCallError::BadParameters(_)) => Err(bad_parameters),
Err(MethodCallError::TooManyDescriptors) => Err(Error::TooManyDescriptors),
Err(e) => Err(Error::BadComponent(e.into())),
}
}
}