From 0894b15c65547b1b6e4af17a45b86251f3decdb5 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Mon, 16 Jun 2025 14:56:24 +0200 Subject: [PATCH 1/2] export some builtin traits, brightness conversion fails for invalid values, macros for wrapping attrs --- Cargo.lock | 4 +- Cargo.toml | 3 + src/brightness.rs | 4 +- src/commands/bitmap.rs | 5 +- src/commands/bitvec.rs | 4 +- src/commands/brightness_grid.rs | 4 +- src/commands/cc_only.rs | 5 +- src/commands/char_grid.rs | 4 +- src/commands/cp437.rs | 4 +- src/commands/global_brightness.rs | 3 +- src/commands/mod.rs | 44 +++++++++--- src/connection.rs | 8 +++ src/containers/bitmap.rs | 12 ++-- src/containers/bitvec.rs | 16 +---- src/containers/brightness_grid.rs | 11 ++- src/containers/char_grid.rs | 40 +++-------- src/containers/cp437_grid.rs | 12 ++-- src/containers/mod.rs | 41 ++++++++++++ src/errors.rs | 2 + src/macros.rs | 107 +++++++++++++++++++++--------- src/packet.rs | 10 +-- 21 files changed, 210 insertions(+), 133 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 486957e..8dfbf55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,8 +426,7 @@ dependencies = [ [[package]] name = "servicepoint" version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91a33bff7f9db5008748b23ca0c906c276fe00694390b681f004a55968a42cfe" +source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint.git?branch=next#5b6f88b1682925b7669b25a7fb08806c4009bbfd" dependencies = [ "bitvec", "bzip2", @@ -443,6 +442,7 @@ dependencies = [ name = "servicepoint_binding_uniffi" version = "0.15.0" dependencies = [ + "paste", "servicepoint", "thiserror 2.0.11", "uniffi", diff --git a/Cargo.toml b/Cargo.toml index d6d0c18..bdc5b47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,10 +19,13 @@ uniffi = { version = "0.28.3", features = ["build"] } [dependencies] uniffi = { version = "0.28.3" } thiserror = "2.0" +paste = "1.0.15" [dependencies.servicepoint] version = "0.15.0" features = ["all_compressions"] +git = "https://git.berlin.ccc.de/servicepoint/servicepoint.git" +branch = "next" [package.metadata.docs.rs] all-features = true diff --git a/src/brightness.rs b/src/brightness.rs index 0ea4591..8efba1e 100644 --- a/src/brightness.rs +++ b/src/brightness.rs @@ -1,3 +1,4 @@ +use crate::errors::ServicePointError; use crate::UniffiCustomTypeConverter; use servicepoint::Brightness; @@ -10,7 +11,8 @@ impl UniffiCustomTypeConverter for Brightness { where Self: Sized, { - Ok(Brightness::saturating_from(val)) + Ok(Brightness::try_from(val) + .map_err(|value| ServicePointError::InvalidBrightness { value })?) } fn from_custom(obj: Self) -> Self::Builtin { diff --git a/src/commands/bitmap.rs b/src/commands/bitmap.rs index 7cda71f..062f3dc 100644 --- a/src/commands/bitmap.rs +++ b/src/commands/bitmap.rs @@ -1,13 +1,14 @@ use crate::{ commands::wrap_command, compression_code::CompressionCode, - containers::bitmap::Bitmap, macros::wrap_object, + containers::bitmap::Bitmap, macros::wrap_object_attr_wrapped, }; use servicepoint::Origin; use std::sync::Arc; -wrap_object!(BitmapCommand); wrap_command!(BitmapCommand); +wrap_object_attr_wrapped!(BitmapCommand, bitmap, Bitmap); + #[uniffi::export] impl BitmapCommand { #[uniffi::constructor] diff --git a/src/commands/bitvec.rs b/src/commands/bitvec.rs index e449ea9..537f95f 100644 --- a/src/commands/bitvec.rs +++ b/src/commands/bitvec.rs @@ -1,11 +1,11 @@ use crate::{ commands::wrap_command, compression_code::CompressionCode, - containers::bitvec::BitVec, macros::wrap_object, + containers::bitvec::BitVec, macros::wrap_object_attr_wrapped, }; use std::sync::Arc; -wrap_object!(BitVecCommand); wrap_command!(BitVecCommand); +wrap_object_attr_wrapped!(BitVecCommand, bitvec, BitVec); #[uniffi::export] impl BitVecCommand { diff --git a/src/commands/brightness_grid.rs b/src/commands/brightness_grid.rs index 29c4e93..d48d8ee 100644 --- a/src/commands/brightness_grid.rs +++ b/src/commands/brightness_grid.rs @@ -1,12 +1,12 @@ use crate::{ commands::wrap_command, containers::brightness_grid::BrightnessGrid, - macros::wrap_object, + macros::wrap_object_attr_wrapped, }; use servicepoint::Origin; use std::sync::Arc; -wrap_object!(BrightnessGridCommand); wrap_command!(BrightnessGridCommand); +wrap_object_attr_wrapped!(BrightnessGridCommand, grid, BrightnessGrid); #[uniffi::export] impl BrightnessGridCommand { diff --git a/src/commands/cc_only.rs b/src/commands/cc_only.rs index b42a79e..576f1e2 100644 --- a/src/commands/cc_only.rs +++ b/src/commands/cc_only.rs @@ -1,10 +1,8 @@ -use crate::{commands::wrap_command, macros::wrap_object}; use std::sync::Arc; macro_rules! command_code_only_command { ($command_struct:ident) => { - wrap_object!($command_struct); - wrap_command!($command_struct); + crate::commands::wrap_command!($command_struct); #[uniffi::export] impl $command_struct { @@ -18,5 +16,4 @@ macro_rules! command_code_only_command { command_code_only_command!(ClearCommand); command_code_only_command!(HardResetCommand); -command_code_only_command!(BitmapLegacyCommand); command_code_only_command!(FadeOutCommand); diff --git a/src/commands/char_grid.rs b/src/commands/char_grid.rs index f02b93e..94da405 100644 --- a/src/commands/char_grid.rs +++ b/src/commands/char_grid.rs @@ -1,12 +1,12 @@ use crate::{ commands::wrap_command, containers::char_grid::CharGrid, - macros::wrap_object, + macros::wrap_object_attr_wrapped, }; use servicepoint::Origin; use std::sync::Arc; -wrap_object!(CharGridCommand); wrap_command!(CharGridCommand); +wrap_object_attr_wrapped!(CharGridCommand, grid, CharGrid); #[uniffi::export] impl CharGridCommand { diff --git a/src/commands/cp437.rs b/src/commands/cp437.rs index f4373c5..59d55a6 100644 --- a/src/commands/cp437.rs +++ b/src/commands/cp437.rs @@ -1,12 +1,12 @@ use crate::{ commands::wrap_command, containers::cp437_grid::Cp437Grid, - macros::wrap_object, + macros::wrap_object_attr_wrapped, }; use servicepoint::Origin; use std::sync::Arc; -wrap_object!(Cp437GridCommand); wrap_command!(Cp437GridCommand); +wrap_object_attr_wrapped!(Cp437GridCommand, grid, Cp437Grid); #[uniffi::export] impl Cp437GridCommand { diff --git a/src/commands/global_brightness.rs b/src/commands/global_brightness.rs index b95977e..5d626e5 100644 --- a/src/commands/global_brightness.rs +++ b/src/commands/global_brightness.rs @@ -1,8 +1,7 @@ -use crate::{commands::wrap_command, macros::wrap_object}; +use crate::commands::wrap_command; use servicepoint::Brightness; use std::sync::Arc; -wrap_object!(GlobalBrightnessCommand); wrap_command!(GlobalBrightnessCommand); #[uniffi::export] diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 224c26d..0773b18 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -8,35 +8,59 @@ mod global_brightness; use std::sync::Arc; -use crate::packet::Packet; pub use bitmap::BitmapCommand; pub use bitvec::{BinaryOperation, BitVecCommand}; pub use brightness_grid::BrightnessGridCommand; -pub use cc_only::{ - BitmapLegacyCommand, ClearCommand, FadeOutCommand, HardResetCommand, -}; +pub use cc_only::{ClearCommand, FadeOutCommand, HardResetCommand}; pub use char_grid::CharGridCommand; pub use cp437::Cp437GridCommand; #[uniffi::export] pub trait Command: Sync + Send { - fn as_packet(&self) -> Option>; + fn as_packet( + &self, + ) -> Result, crate::errors::ServicePointError>; } macro_rules! wrap_command { ($command:ident) => { - #[uniffi::export] - impl $command {} + crate::macros::wrap_object!($command); - impl crate::commands::Command for $command { - fn as_packet(&self) -> Option> { + #[uniffi::export] + impl $command { + fn as_packet( + &self, + ) -> Result< + Arc, + crate::errors::ServicePointError, + > { self.read() .clone() .try_into() .map(crate::packet::Packet::internal_new) - .ok() + .map_err(|_| { + crate::errors::ServicePointError::InvalidPacket + }) + } + + fn as_generic( + &self, + ) -> ::std::sync::Arc { + ::std::sync::Arc::new(self.clone()) + } + } + + impl crate::commands::Command for $command { + fn as_packet( + &self, + ) -> Result< + Arc, + crate::errors::ServicePointError, + > { + $command::as_packet(&self) } } }; } + pub(crate) use wrap_command; diff --git a/src/connection.rs b/src/connection.rs index 9f1f0e0..5b9ed52 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,3 +1,4 @@ +use crate::commands::Command; use crate::{errors::ServicePointError, packet::Packet}; use servicepoint::UdpSocketExt; use std::{net::UdpSocket, sync::Arc}; @@ -28,4 +29,11 @@ impl Connection { error: "send failed".to_string(), }) } + + pub fn send_command( + &self, + command: Arc, + ) -> Result<(), ServicePointError> { + self.send_packet(command.as_packet()?) + } } diff --git a/src/containers/bitmap.rs b/src/containers/bitmap.rs index 7598609..1418e5e 100644 --- a/src/containers/bitmap.rs +++ b/src/containers/bitmap.rs @@ -1,4 +1,7 @@ -use crate::macros::*; +use crate::{ + containers::{wrap_get_set_fill_2d, wrap_width_height}, + macros::wrap_object, +}; use servicepoint::Grid; use std::{ops::Deref, sync::Arc}; @@ -22,18 +25,13 @@ impl Bitmap { #[uniffi::constructor] pub fn load(width: u64, height: u64, data: Vec) -> Arc { + // TODO: throw exception Self::internal_new( servicepoint::Bitmap::load(width as usize, height as usize, &data) .unwrap(), ) } - pub fn equals(&self, other: &Bitmap) -> bool { - let a = self.read(); - let b = other.read(); - *a == *b - } - pub fn copy_raw(&self) -> Vec { self.read().deref().into() } diff --git a/src/containers/bitvec.rs b/src/containers/bitvec.rs index b5686d9..cd2c87d 100644 --- a/src/containers/bitvec.rs +++ b/src/containers/bitvec.rs @@ -18,31 +18,21 @@ impl BitVec { } pub fn set(&self, index: u64, value: bool) { - self.actual.write().unwrap().set(index as usize, value) + self.write().set(index as usize, value) } pub fn get(&self, index: u64) -> bool { - self.actual - .read() - .unwrap() - .get(index as usize) - .is_some_and(move |bit| *bit) + self.read().get(index as usize).is_some_and(move |bit| *bit) } pub fn fill(&self, value: bool) { - self.actual.write().unwrap().fill(value) + self.write().fill(value) } pub fn len(&self) -> u64 { self.read().len() as u64 } - pub fn equals(&self, other: &BitVec) -> bool { - let a = self.read(); - let b = other.read(); - *a == *b - } - pub fn copy_raw(&self) -> Vec { self.read().clone().into_vec() } diff --git a/src/containers/brightness_grid.rs b/src/containers/brightness_grid.rs index 6e99211..6bb3cbc 100644 --- a/src/containers/brightness_grid.rs +++ b/src/containers/brightness_grid.rs @@ -1,4 +1,7 @@ -use crate::macros::*; +use crate::{ + containers::{wrap_get_set_fill_2d, wrap_width_height}, + macros::wrap_object, +}; use servicepoint::{Brightness, Grid}; use std::{ops::Deref, sync::Arc}; @@ -28,12 +31,6 @@ impl BrightnessGrid { ) } - pub fn equals(&self, other: &BrightnessGrid) -> bool { - let a = self.read(); - let b = other.read(); - *a == *b - } - pub fn copy_raw(&self) -> Vec { self.read().deref().into() } diff --git a/src/containers/char_grid.rs b/src/containers/char_grid.rs index 2863282..387344c 100644 --- a/src/containers/char_grid.rs +++ b/src/containers/char_grid.rs @@ -1,4 +1,7 @@ -use crate::{containers::cp437_grid::Cp437Grid, macros::*}; +use crate::{ + containers::{cp437_grid::Cp437Grid, wrap_width_height}, + macros::wrap_object, +}; use servicepoint::{Grid, SetValueSeriesError}; use std::{convert::Into, sync::Arc}; @@ -37,58 +40,39 @@ impl CharGrid { value: String, ) -> Result<(), CharGridError> { let value = Self::str_to_char(value)?; - self.actual - .write() - .unwrap() - .set(x as usize, y as usize, value); + self.write().set(x as usize, y as usize, value); Ok(()) } pub fn get(&self, x: u64, y: u64) -> String { - self.actual - .read() - .unwrap() - .get(x as usize, y as usize) - .into() + self.read().get(x as usize, y as usize).into() } pub fn fill(&self, value: String) -> Result<(), CharGridError> { let value = Self::str_to_char(value)?; - self.actual.write().unwrap().fill(value); + self.write().fill(value); Ok(()) } - pub fn equals(&self, other: &CharGrid) -> bool { - let a = self.read(); - let b = other.read(); - *a == *b - } - pub fn as_string(&self) -> String { let grid = self.read(); String::from(&*grid) } pub fn set_row(&self, y: u64, row: String) -> Result<(), CharGridError> { - self.actual - .write() - .unwrap() + self.write() .set_row(y as usize, &row.chars().collect::>()) .map_err(CharGridError::from) } pub fn set_col(&self, x: u64, col: String) -> Result<(), CharGridError> { - self.actual - .write() - .unwrap() + self.write() .set_row(x as usize, &col.chars().collect::>()) .map_err(CharGridError::from) } pub fn get_row(&self, y: u64) -> Result { - self.actual - .read() - .unwrap() + self.read() .get_row(y as usize) .map(String::from_iter) .ok_or(CharGridError::OutOfBounds { @@ -98,9 +82,7 @@ impl CharGrid { } pub fn get_col(&self, x: u64) -> Result { - self.actual - .read() - .unwrap() + self.read() .get_col(x as usize) .map(String::from_iter) .ok_or(CharGridError::OutOfBounds { diff --git a/src/containers/cp437_grid.rs b/src/containers/cp437_grid.rs index bdcbfc1..fdd25e0 100644 --- a/src/containers/cp437_grid.rs +++ b/src/containers/cp437_grid.rs @@ -1,4 +1,8 @@ -use crate::{containers::char_grid::CharGrid, macros::*}; +use crate::{ + containers::char_grid::CharGrid, + containers::{wrap_get_set_fill_2d, wrap_width_height}, + macros::wrap_object, +}; use servicepoint::Grid; use std::{ops::Deref, sync::Arc}; @@ -28,12 +32,6 @@ impl Cp437Grid { ) } - pub fn equals(&self, other: &Cp437Grid) -> bool { - let a = self.read(); - let b = other.read(); - *a == *b - } - pub fn copy_raw(&self) -> Vec { self.read().deref().into() } diff --git a/src/containers/mod.rs b/src/containers/mod.rs index 7dce8bd..f1d4880 100644 --- a/src/containers/mod.rs +++ b/src/containers/mod.rs @@ -3,3 +3,44 @@ pub mod bitvec; pub mod brightness_grid; pub mod char_grid; pub mod cp437_grid; + +macro_rules! wrap_width_height { + ($t:ident) => { + #[uniffi::export] + impl $t { + pub fn width(&self) -> u64 { + self.read().width() as u64 + } + + pub fn height(&self) -> u64 { + self.read().height() as u64 + } + } + }; +} + +pub(crate) use wrap_width_height; + +macro_rules! wrap_get_set_fill_2d { + ($t:ident, $contained:ident) => { + #[uniffi::export] + impl $t { + pub fn set(&self, x: u64, y: u64, value: $contained) { + self.actual + .write() + .unwrap() + .set(x as usize, y as usize, value) + } + + pub fn get(&self, x: u64, y: u64) -> $contained { + self.read().get(x as usize, y as usize) + } + + pub fn fill(&self, value: $contained) { + self.actual.write().unwrap().fill(value) + } + } + }; +} + +pub(crate) use wrap_get_set_fill_2d; diff --git a/src/errors.rs b/src/errors.rs index 9c28f5f..03d05ba 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -4,4 +4,6 @@ pub enum ServicePointError { IoError { error: String }, #[error("The specified brightness value {value} is out of range")] InvalidBrightness { value: u8 }, + #[error("The provided packet is invalid or a conversion to packet failed")] + InvalidPacket, } diff --git a/src/macros.rs b/src/macros.rs index ee15b5e..140b42c 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,6 +1,7 @@ macro_rules! wrap_object { ($orig_t:ident, $new_t:ident) => { #[derive(uniffi::Object)] + #[uniffi::export(Debug, Eq, Hash)] pub struct $new_t { actual: ::std::sync::RwLock<::servicepoint::$orig_t>, } @@ -10,9 +11,15 @@ macro_rules! wrap_object { pub(crate) fn internal_new( actual: ::servicepoint::$orig_t, ) -> ::std::sync::Arc { - ::std::sync::Arc::new(Self { + ::std::sync::Arc::new(Self::internal_new_noarc(actual)) + } + + pub(crate) fn internal_new_noarc( + actual: ::servicepoint::$orig_t, + ) -> Self { + Self { actual: ::std::sync::RwLock::new(actual), - }) + } } pub(crate) fn read( @@ -37,51 +44,85 @@ macro_rules! wrap_object { Self::internal_new(other.read().clone()) } } + + impl Clone for $new_t { + fn clone(&self) -> Self { + Self::internal_new_noarc(self.read().clone()) + } + } + + impl ::std::fmt::Debug for $new_t { + fn fmt( + &self, + f: &mut ::std::fmt::Formatter, + ) -> Result<(), std::fmt::Error> { + f.write_fmt(format_args!("{:?}", self.read())) + } + } + + impl PartialEq for $new_t { + fn eq(&self, other: &$new_t) -> bool { + *self.read() == *other.read() + } + } + + impl Eq for $new_t {} + + impl ::std::hash::Hash for $new_t { + fn hash(&self, state: &mut H) { + ::std::hash::Hash::hash(&*self.read(), state) + } + } }; ($t:ident) => { - wrap_object!($t, $t); + crate::macros::wrap_object!($t, $t); }; } -pub(crate) use wrap_object; - -macro_rules! wrap_width_height { - ($t:ident) => { +macro_rules! wrap_object_attr_wrapped_get { + ($object:ident, $attr_name:ident, $attr_type:ident, $fun_name:ident) => { #[uniffi::export] - impl $t { - pub fn width(&self) -> u64 { - self.read().width() as u64 - } - - pub fn height(&self) -> u64 { - self.read().height() as u64 + impl $object { + pub fn $fun_name(&self) -> ::std::sync::Arc<$attr_type> { + $attr_type::internal_new(self.read().$attr_name.clone()) } } }; + ($object:ident, $attr_name:ident, $attr_type:ident) => { + paste::paste!{ + crate::macros::wrap_object_attr_wrapped_get!($object, $attr_name, $attr_type, []); + } + }; } -pub(crate) use wrap_width_height; - -macro_rules! wrap_get_set_fill_2d { - ($t:ident, $contained:ident) => { +macro_rules! wrap_object_attr_wrapped_set { + ($object:ident, $attr_name:ident, $attr_type:ident, $fun_name:ident) => { #[uniffi::export] - impl $t { - pub fn set(&self, x: u64, y: u64, value: $contained) { - self.actual - .write() - .unwrap() - .set(x as usize, y as usize, value) - } - - pub fn get(&self, x: u64, y: u64) -> $contained { - self.read().get(x as usize, y as usize) - } - - pub fn fill(&self, value: $contained) { - self.actual.write().unwrap().fill(value) + impl $object { + pub fn $fun_name(&self, $attr_name: ::std::sync::Arc<$attr_type>) { + self.write().$attr_name = $attr_name.read().clone(); } } }; + ($object:ident, $attr_name:ident, $attr_type:ident) => { + paste::paste!{ + crate::macros::wrap_object_attr_wrapped_set!($object, $attr_name, $attr_type, []); + } + }; } -pub(crate) use wrap_get_set_fill_2d; +macro_rules! wrap_object_attr_wrapped { + ($object:ident, $attr_name:ident, $attr_type:ident) => { + crate::macros::wrap_object_attr_wrapped_get!( + $object, $attr_name, $attr_type + ); + crate::macros::wrap_object_attr_wrapped_set!( + $object, $attr_name, $attr_type + ); + }; +} + +pub(crate) use { + wrap_object, wrap_object_attr_wrapped, wrap_object_attr_wrapped_get, + wrap_object_attr_wrapped_set, +}; diff --git a/src/packet.rs b/src/packet.rs index 5f769f1..ceaf052 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,12 +1,6 @@ -use crate::macros::wrap_object; -use std::sync::Arc; +use crate::macros::{wrap_object, wrap_object_attr_wrapped}; wrap_object!(Packet); wrap_object!(Header); -#[uniffi::export] -impl Packet { - pub fn get_header(&self) -> Arc
{ - Header::internal_new(self.read().header) - } -} +wrap_object_attr_wrapped!(Packet, header, Header); From ecb4f51997d4f2c3f5bd66033ef13992d88c139c Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Mon, 16 Jun 2025 16:37:20 +0200 Subject: [PATCH 2/2] partially fix tests --- src/compression_code.rs | 20 +++++++++- src/containers/char_grid.rs | 76 ++++++++++++++++++------------------- src/errors.rs | 6 +++ src/packet.rs | 7 ++++ 4 files changed, 67 insertions(+), 42 deletions(-) diff --git a/src/compression_code.rs b/src/compression_code.rs index a3d332d..bf530f1 100644 --- a/src/compression_code.rs +++ b/src/compression_code.rs @@ -15,12 +15,28 @@ pub enum CompressionCode { impl From for CompressionCode { fn from(value: servicepoint::CompressionCode) -> Self { - value.into() + match value { + servicepoint::CompressionCode::Uncompressed => { + CompressionCode::Uncompressed + } + servicepoint::CompressionCode::Zlib => CompressionCode::Zlib, + servicepoint::CompressionCode::Bzip2 => CompressionCode::Bzip2, + servicepoint::CompressionCode::Lzma => CompressionCode::Lzma, + servicepoint::CompressionCode::Zstd => CompressionCode::Zstd, + } } } impl From for servicepoint::CompressionCode { fn from(value: CompressionCode) -> Self { - servicepoint::CompressionCode::try_from(value).unwrap() + match value { + CompressionCode::Uncompressed => { + servicepoint::CompressionCode::Uncompressed + } + CompressionCode::Zlib => servicepoint::CompressionCode::Zlib, + CompressionCode::Bzip2 => servicepoint::CompressionCode::Bzip2, + CompressionCode::Lzma => servicepoint::CompressionCode::Lzma, + CompressionCode::Zstd => servicepoint::CompressionCode::Zstd, + } } } diff --git a/src/containers/char_grid.rs b/src/containers/char_grid.rs index 387344c..28712be 100644 --- a/src/containers/char_grid.rs +++ b/src/containers/char_grid.rs @@ -1,23 +1,14 @@ use crate::{ containers::{cp437_grid::Cp437Grid, wrap_width_height}, + errors::ServicePointError, macros::wrap_object, }; use servicepoint::{Grid, SetValueSeriesError}; -use std::{convert::Into, sync::Arc}; +use std::sync::Arc; wrap_object!(CharGrid); wrap_width_height!(CharGrid); -#[derive(uniffi::Error, thiserror::Error, Debug)] -pub enum CharGridError { - #[error("Exactly one character was expected, but {value:?} was provided")] - StringNotOneChar { value: String }, - #[error("The provided series was expected to have a length of {expected}, but was {actual}")] - InvalidSeriesLength { actual: u64, expected: u64 }, - #[error("The index {index} was out of bounds for size {size}")] - OutOfBounds { index: u64, size: u64 }, -} - #[uniffi::export] impl CharGrid { #[uniffi::constructor] @@ -38,17 +29,23 @@ impl CharGrid { x: u64, y: u64, value: String, - ) -> Result<(), CharGridError> { + ) -> Result<(), ServicePointError> { let value = Self::str_to_char(value)?; - self.write().set(x as usize, y as usize, value); - Ok(()) + if self.write().set_optional(x as isize, y as isize, value) { + Ok(()) + } else { + Err(ServicePointError::OutOfBounds) + } } - pub fn get(&self, x: u64, y: u64) -> String { - self.read().get(x as usize, y as usize).into() + pub fn get(&self, x: u64, y: u64) -> Result { + self.read() + .get_optional(x as isize, y as isize) + .ok_or(ServicePointError::OutOfBounds) + .map(String::from) } - pub fn fill(&self, value: String) -> Result<(), CharGridError> { + pub fn fill(&self, value: String) -> Result<(), ServicePointError> { let value = Self::str_to_char(value)?; self.write().fill(value); Ok(()) @@ -59,36 +56,38 @@ impl CharGrid { String::from(&*grid) } - pub fn set_row(&self, y: u64, row: String) -> Result<(), CharGridError> { + pub fn set_row( + &self, + y: u64, + row: String, + ) -> Result<(), ServicePointError> { self.write() .set_row(y as usize, &row.chars().collect::>()) - .map_err(CharGridError::from) + .map_err(ServicePointError::from) } - pub fn set_col(&self, x: u64, col: String) -> Result<(), CharGridError> { + pub fn set_col( + &self, + x: u64, + col: String, + ) -> Result<(), ServicePointError> { self.write() .set_row(x as usize, &col.chars().collect::>()) - .map_err(CharGridError::from) + .map_err(ServicePointError::from) } - pub fn get_row(&self, y: u64) -> Result { + pub fn get_row(&self, y: u64) -> Result { self.read() .get_row(y as usize) .map(String::from_iter) - .ok_or(CharGridError::OutOfBounds { - index: y, - size: self.height(), - }) + .ok_or(ServicePointError::OutOfBounds) } - pub fn get_col(&self, x: u64) -> Result { + pub fn get_col(&self, x: u64) -> Result { self.read() .get_col(x as usize) .map(String::from_iter) - .ok_or(CharGridError::OutOfBounds { - index: x, - size: self.width(), - }) + .ok_or(ServicePointError::OutOfBounds) } pub fn to_cp437(&self) -> Arc { @@ -97,9 +96,9 @@ impl CharGrid { } impl CharGrid { - fn str_to_char(value: String) -> Result { + fn str_to_char(value: String) -> Result { if value.len() != 1 { - return Err(CharGridError::StringNotOneChar { value }); + return Err(ServicePointError::StringNotOneChar { value }); } let value = value.chars().nth(0).unwrap(); @@ -107,17 +106,14 @@ impl CharGrid { } } -impl From for CharGridError { +impl From for ServicePointError { fn from(e: SetValueSeriesError) -> Self { match e { - SetValueSeriesError::OutOfBounds { index, size } => { - CharGridError::OutOfBounds { - index: index as u64, - size: size as u64, - } + SetValueSeriesError::OutOfBounds { .. } => { + ServicePointError::OutOfBounds } SetValueSeriesError::InvalidLength { actual, expected } => { - CharGridError::InvalidSeriesLength { + ServicePointError::InvalidSeriesLength { actual: actual as u64, expected: expected as u64, } diff --git a/src/errors.rs b/src/errors.rs index 03d05ba..f234278 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -6,4 +6,10 @@ pub enum ServicePointError { InvalidBrightness { value: u8 }, #[error("The provided packet is invalid or a conversion to packet failed")] InvalidPacket, + #[error("Exactly one character was expected, but {value:?} was provided")] + StringNotOneChar { value: String }, + #[error("The provided series was expected to have a length of {expected}, but was {actual}")] + InvalidSeriesLength { actual: u64, expected: u64 }, + #[error("The index was out of bounds")] + OutOfBounds, } diff --git a/src/packet.rs b/src/packet.rs index ceaf052..bdfd0a8 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -4,3 +4,10 @@ wrap_object!(Packet); wrap_object!(Header); wrap_object_attr_wrapped!(Packet, header, Header); + +#[uniffi::export] +impl Packet { + pub fn as_bytes(&self) -> Vec { + Vec::from(&*self.read()) + } +}