use crate::common::{Colour, COLOURS};
use crate::error::Error;
use crate::helpers::Ignore;
use minicbor::{Decode, Encode};
use oc_wasm_futures::invoke::{component_method, Buffer};
use oc_wasm_helpers::{
sides::{Side, BLOCK_SIDES},
Lockable,
};
use oc_wasm_safe::{component::Invoker, Address};
pub const TYPE: &str = "redstone";
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Redstone(Address);
impl Redstone {
#[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 Redstone {
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_input(&mut self) -> Result<[u8; BLOCK_SIDES], Error> {
self.get_vanilla("getInput").await
}
pub async fn get_side_input(&mut self, side: impl Side) -> Result<u8, Error> {
self.get_side_vanilla("getInput", side.into()).await
}
pub async fn get_bundled_input(&mut self) -> Result<[[u8; COLOURS]; BLOCK_SIDES], Error> {
self.get_bundled("getBundledInput").await
}
pub async fn get_side_bundled_input(
&mut self,
side: impl Side,
) -> Result<[u8; COLOURS], Error> {
self.get_side_bundled("getBundledInput", side.into()).await
}
pub async fn get_side_colour_bundled_input(
&mut self,
side: impl Side,
colour: Colour,
) -> Result<u8, Error> {
self.get_side_colour_bundled("getBundledInput", side.into(), colour.into())
.await
}
pub async fn get_output(&mut self) -> Result<[u8; BLOCK_SIDES], Error> {
self.get_vanilla("getOutput").await
}
pub async fn get_side_output(&mut self, side: impl Side) -> Result<u8, Error> {
self.get_side_vanilla("getOutput", side.into()).await
}
pub async fn get_bundled_output(&mut self) -> Result<[[u8; COLOURS]; BLOCK_SIDES], Error> {
self.get_bundled("getBundledOutput").await
}
pub async fn get_side_bundled_output(
&mut self,
side: impl Side,
) -> Result<[u8; COLOURS], Error> {
self.get_side_bundled("getBundledOutput", side.into()).await
}
pub async fn get_side_colour_bundled_output(
&mut self,
side: impl Side,
colour: Colour,
) -> Result<u8, Error> {
self.get_side_colour_bundled("getBundledOutput", side.into(), colour.into())
.await
}
pub async fn set_output(
&mut self,
levels: &[Option<u8>; BLOCK_SIDES],
) -> Result<[u8; BLOCK_SIDES], Error> {
let ret: (ArrayAsMap<u8, BLOCK_SIDES>,) = component_method(
self.invoker,
self.buffer,
&self.address,
"setOutput",
Some(&(ArrayAsMap(*levels),)),
)
.await?;
Ok(ret.0 .0)
}
pub async fn set_side_output(&mut self, side: impl Side, level: u8) -> Result<u8, Error> {
let side: u8 = side.into();
let ret: (u8,) = component_method(
self.invoker,
self.buffer,
&self.address,
"setOutput",
Some(&(side, level)),
)
.await?;
Ok(ret.0)
}
pub async fn set_bundled_output(
&mut self,
levels: &[[Option<u8>; COLOURS]; BLOCK_SIDES],
) -> Result<(), Error> {
let param: (ArrayAsMap<ArrayAsMap<Option<u8>, COLOURS>, BLOCK_SIDES>,) = (ArrayAsMap([
ArrayAsMap(levels[0]),
ArrayAsMap(levels[1]),
ArrayAsMap(levels[2]),
ArrayAsMap(levels[3]),
ArrayAsMap(levels[4]),
ArrayAsMap(levels[5]),
]),);
component_method::<_, Ignore, _>(
self.invoker,
self.buffer,
&self.address,
"setBundledOutput",
Some(¶m),
)
.await?;
Ok(())
}
pub async fn set_side_bundled_output(
&mut self,
side: impl Side,
levels: &[Option<u8>; COLOURS],
) -> Result<(), Error> {
let side: u8 = side.into();
component_method::<_, Ignore, _>(
self.invoker,
self.buffer,
&self.address,
"setBundledOutput",
Some(&(side, ArrayAsMap(*levels))),
)
.await?;
Ok(())
}
pub async fn set_side_colour_bundled_output(
&mut self,
side: impl Side,
colour: Colour,
level: u8,
) -> Result<u8, Error> {
let side: u8 = side.into();
let colour: u8 = colour.into();
let ret: (u8,) = component_method(
self.invoker,
self.buffer,
&self.address,
"setBundledOutput",
Some(&(side, colour, level)),
)
.await?;
Ok(ret.0)
}
pub async fn get_comparator_input(&mut self, side: impl Side) -> Result<u8, Error> {
let side: u8 = side.into();
let ret: (u8,) = component_method(
self.invoker,
self.buffer,
&self.address,
"getComparatorInput",
Some(&(side,)),
)
.await?;
Ok(ret.0)
}
pub async fn get_wake_threshold(&mut self) -> Result<u32, Error> {
let ret: (u32,) = component_method::<(), _, _>(
self.invoker,
self.buffer,
&self.address,
"getWakeThreshold",
None,
)
.await?;
Ok(ret.0)
}
pub async fn set_wake_threshold(&mut self, threshold: u32) -> Result<u32, Error> {
let ret: (u32,) = component_method(
self.invoker,
self.buffer,
&self.address,
"setWakeThreshold",
Some(&(threshold,)),
)
.await?;
Ok(ret.0)
}
async fn get_vanilla(&mut self, method: &str) -> Result<[u8; BLOCK_SIDES], Error> {
let ret: (ArrayAsMap<u8, BLOCK_SIDES>,) =
component_method::<(), _, _>(self.invoker, self.buffer, &self.address, method, None)
.await?;
Ok(ret.0 .0)
}
async fn get_side_vanilla(&mut self, method: &str, side: u8) -> Result<u8, Error> {
let ret: (u8,) = component_method(
self.invoker,
self.buffer,
&self.address,
method,
Some(&(side,)),
)
.await?;
Ok(ret.0)
}
async fn get_bundled(&mut self, method: &str) -> Result<[[u8; COLOURS]; BLOCK_SIDES], Error> {
let ret: (ArrayAsMap<ArrayAsMap<u8, COLOURS>, BLOCK_SIDES>,) =
component_method::<(), _, _>(self.invoker, self.buffer, &self.address, method, None)
.await?;
Ok([
ret.0 .0[0].0,
ret.0 .0[1].0,
ret.0 .0[2].0,
ret.0 .0[3].0,
ret.0 .0[4].0,
ret.0 .0[5].0,
])
}
async fn get_side_bundled(&mut self, method: &str, side: u8) -> Result<[u8; COLOURS], Error> {
let ret: (ArrayAsMap<u8, COLOURS>,) = component_method(
self.invoker,
self.buffer,
&self.address,
method,
Some(&(side,)),
)
.await?;
Ok(ret.0 .0)
}
async fn get_side_colour_bundled(
&mut self,
method: &str,
side: u8,
colour: u8,
) -> Result<u8, Error> {
let ret: (u8,) = component_method(
self.invoker,
self.buffer,
&self.address,
method,
Some(&(side, colour)),
)
.await?;
Ok(ret.0)
}
}
#[derive(Clone, Copy)]
struct ArrayAsMap<T, const LENGTH: usize>(pub [T; LENGTH]);
impl<'buffer, Context, T: Copy + Decode<'buffer, Context> + Default, const LENGTH: usize>
Decode<'buffer, Context> for ArrayAsMap<T, LENGTH>
{
fn decode(
d: &mut minicbor::Decoder<'buffer>,
context: &mut Context,
) -> Result<Self, minicbor::decode::Error> {
let mut ret = [T::default(); LENGTH];
#[allow(clippy::cast_possible_truncation)]
let length = d
.map()?
.ok_or_else(|| minicbor::decode::Error::message(""))? as usize;
for _ in 0..length {
let key = d.u32()?;
ret[key as usize] = d.decode_with(context)?;
}
Ok(Self(ret))
}
}
impl<Context, T: Encode<Context>, const LENGTH: usize> Encode<Context>
for ArrayAsMap<Option<T>, LENGTH>
{
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
context: &mut Context,
) -> Result<(), minicbor::encode::Error<W::Error>> {
let count = self.0.iter().filter(|i| i.is_some()).count();
e.map(count as u64)?;
for i in 0..LENGTH {
if let Some(elt) = &self.0[i] {
e.u64(i as u64)?;
e.encode_with(elt, context)?;
}
}
Ok(())
}
}
impl<Context, T: Encode<Context>, const INNER_LENGTH: usize, const OUTER_LENGTH: usize>
Encode<Context> for ArrayAsMap<ArrayAsMap<Option<T>, INNER_LENGTH>, OUTER_LENGTH>
{
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
context: &mut Context,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.map(OUTER_LENGTH as u64)?;
for i in 0..OUTER_LENGTH {
e.u64(i as u64)?;
e.encode_with(&self.0[i], context)?;
}
Ok(())
}
}
impl<T, const LENGTH: usize> Default for ArrayAsMap<T, LENGTH>
where
[T; LENGTH]: Default,
{
fn default() -> Self {
Self(Default::default())
}
}