diff --git a/Cargo.lock b/Cargo.lock index 30036a5..8dfbf55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "adler2" @@ -209,9 +209,9 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "goblin" -version = "0.6.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" dependencies = [ "log", "plain", @@ -220,9 +220,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "itoa" @@ -304,12 +304,6 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" -[[package]] -name = "oneshot-uniffi" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c" - [[package]] name = "paste" version = "1.0.15" @@ -370,18 +364,18 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "scroll" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" dependencies = [ "scroll_derive", ] [[package]] name = "scroll_derive" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" +checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", @@ -431,9 +425,8 @@ dependencies = [ [[package]] name = "servicepoint" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93b52049be55a15fe37c13249d7f96aa8a5de56e1a41838e74a822ee8316a0c4" +version = "0.15.0" +source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint.git?branch=next#5b6f88b1682925b7669b25a7fb08806c4009bbfd" dependencies = [ "bitvec", "bzip2", @@ -447,8 +440,9 @@ dependencies = [ [[package]] name = "servicepoint_binding_uniffi" -version = "0.13.1" +version = "0.15.0" dependencies = [ + "paste", "servicepoint", "thiserror 2.0.11", "uniffi", @@ -466,6 +460,12 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + [[package]] name = "static_assertions" version = "1.1.0" @@ -489,6 +489,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -552,11 +561,13 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "uniffi" -version = "0.25.3" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21345172d31092fd48c47fd56c53d4ae9e41c4b1f559fb8c38c1ab1685fd919f" +checksum = "4cb08c58c7ed7033150132febe696bef553f891b1ede57424b40d87a89e3c170" dependencies = [ "anyhow", + "cargo_metadata", + "uniffi_bindgen", "uniffi_build", "uniffi_core", "uniffi_macros", @@ -564,9 +575,9 @@ dependencies = [ [[package]] name = "uniffi_bindgen" -version = "0.25.3" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd992f2929a053829d5875af1eff2ee3d7a7001cb3b9a46cc7895f2caede6940" +checksum = "cade167af943e189a55020eda2c314681e223f1e42aca7c4e52614c2b627698f" dependencies = [ "anyhow", "askama", @@ -579,17 +590,17 @@ dependencies = [ "once_cell", "paste", "serde", + "textwrap", "toml", "uniffi_meta", - "uniffi_testing", "uniffi_udl", ] [[package]] name = "uniffi_build" -version = "0.25.3" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "001964dd3682d600084b3aaf75acf9c3426699bc27b65e96bb32d175a31c74e9" +checksum = "4c7cf32576e08104b7dc2a6a5d815f37616e66c6866c2a639fe16e6d2286b75b" dependencies = [ "anyhow", "camino", @@ -598,9 +609,9 @@ dependencies = [ [[package]] name = "uniffi_checksum_derive" -version = "0.25.3" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55137c122f712d9330fd985d66fa61bdc381752e89c35708c13ce63049a3002c" +checksum = "802d2051a700e3ec894c79f80d2705b69d85844dafbbe5d1a92776f8f48b563a" dependencies = [ "quote", "syn", @@ -608,25 +619,23 @@ dependencies = [ [[package]] name = "uniffi_core" -version = "0.25.3" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6121a127a3af1665cd90d12dd2b3683c2643c5103281d0fed5838324ca1fad5b" +checksum = "bc7687007d2546c454d8ae609b105daceb88175477dac280707ad6d95bcd6f1f" dependencies = [ "anyhow", "bytes", - "camino", "log", "once_cell", - "oneshot-uniffi", "paste", "static_assertions", ] [[package]] name = "uniffi_macros" -version = "0.25.3" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11cf7a58f101fcedafa5b77ea037999b88748607f0ef3a33eaa0efc5392e92e4" +checksum = "12c65a5b12ec544ef136693af8759fb9d11aefce740fb76916721e876639033b" dependencies = [ "bincode", "camino", @@ -637,15 +646,14 @@ dependencies = [ "serde", "syn", "toml", - "uniffi_build", "uniffi_meta", ] [[package]] name = "uniffi_meta" -version = "0.25.3" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71dc8573a7b1ac4b71643d6da34888273ebfc03440c525121f1b3634ad3417a2" +checksum = "4a74ed96c26882dac1ca9b93ca23c827e284bacbd7ec23c6f0b0372f747d59e4" dependencies = [ "anyhow", "bytes", @@ -655,9 +663,9 @@ dependencies = [ [[package]] name = "uniffi_testing" -version = "0.25.3" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "118448debffcb676ddbe8c5305fb933ab7e0123753e659a71dc4a693f8d9f23c" +checksum = "6a6f984f0781f892cc864a62c3a5c60361b1ccbd68e538e6c9fbced5d82268ac" dependencies = [ "anyhow", "camino", @@ -668,11 +676,12 @@ dependencies = [ [[package]] name = "uniffi_udl" -version = "0.25.3" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "889edb7109c6078abe0e53e9b4070cf74a6b3468d141bdf5ef1bd4d1dc24a1c3" +checksum = "037820a4cfc4422db1eaa82f291a3863c92c7d1789dc513489c36223f9b4cdfc" dependencies = [ "anyhow", + "textwrap", "uniffi_meta", "uniffi_testing", "weedle2", @@ -686,9 +695,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "weedle2" -version = "4.0.0" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e79c5206e1f43a2306fd64bdb95025ee4228960f2e6c5a8b173f3caaf807741" +checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" dependencies = [ "nom", ] diff --git a/Cargo.toml b/Cargo.toml index 516cbf5..bdc5b47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "servicepoint_binding_uniffi" -version = "0.13.1" +version = "0.15.0" publish = false edition = "2021" license = "GPL-3.0-or-later" @@ -14,15 +14,18 @@ keywords = ["cccb", "cccb-servicepoint", "uniffi"] crate-type = ["cdylib"] [build-dependencies] -uniffi = { version = "0.25.3", features = ["build"] } +uniffi = { version = "0.28.3", features = ["build"] } [dependencies] -uniffi = { version = "0.25.3" } +uniffi = { version = "0.28.3" } thiserror = "2.0" +paste = "1.0.15" [dependencies.servicepoint] -version = "0.13.1" +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/flake.lock b/flake.lock index 9e70e85..f51971e 100644 --- a/flake.lock +++ b/flake.lock @@ -2,16 +2,16 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1739357830, - "narHash": "sha256-9xim3nJJUFbVbJCz48UP4fGRStVW5nv4VdbimbKxJ3I=", + "lastModified": 1749494155, + "narHash": "sha256-FG4DEYBpROupu758beabUk9lhrblSf5hnv84v1TLqMc=", "owner": "nixos", "repo": "nixpkgs", - "rev": "0ff09db9d034a04acd4e8908820ba0b410d7a33a", + "rev": "88331c17ba434359491e8d5889cce872464052c2", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixos-24.11", + "ref": "nixos-25.05", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index f619fe0..60cfbb6 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,7 @@ description = "Flake for the servicepoint library."; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05"; }; outputs = diff --git a/src/bitmap.rs b/src/bitmap.rs deleted file mode 100644 index 1291f7b..0000000 --- a/src/bitmap.rs +++ /dev/null @@ -1,77 +0,0 @@ -use servicepoint::{DataRef, Grid}; -use std::sync::{Arc, RwLock}; - -#[derive(uniffi::Object)] -pub struct Bitmap { - pub(crate) actual: RwLock, -} - -impl Bitmap { - fn internal_new(actual: servicepoint::Bitmap) -> Arc { - Arc::new(Self { - actual: RwLock::new(actual), - }) - } -} - -#[uniffi::export] -impl Bitmap { - #[uniffi::constructor] - pub fn new(width: u64, height: u64) -> Arc { - Self::internal_new(servicepoint::Bitmap::new( - width as usize, - height as usize, - )) - } - - #[uniffi::constructor] - pub fn new_max_sized() -> Arc { - Self::internal_new(servicepoint::Bitmap::max_sized()) - } - - #[uniffi::constructor] - pub fn load(width: u64, height: u64, data: Vec) -> Arc { - Self::internal_new(servicepoint::Bitmap::load( - width as usize, - height as usize, - &data, - )) - } - - #[uniffi::constructor] - pub fn clone(other: &Arc) -> Arc { - Self::internal_new(other.actual.read().unwrap().clone()) - } - - pub fn set(&self, x: u64, y: u64, value: bool) { - self.actual - .write() - .unwrap() - .set(x as usize, y as usize, value) - } - - pub fn get(&self, x: u64, y: u64) -> bool { - self.actual.read().unwrap().get(x as usize, y as usize) - } - - pub fn fill(&self, value: bool) { - self.actual.write().unwrap().fill(value) - } - pub fn width(&self) -> u64 { - self.actual.read().unwrap().width() as u64 - } - - pub fn height(&self) -> u64 { - self.actual.read().unwrap().height() as u64 - } - - pub fn equals(&self, other: &Bitmap) -> bool { - let a = self.actual.read().unwrap(); - let b = other.actual.read().unwrap(); - *a == *b - } - - pub fn copy_raw(&self) -> Vec { - self.actual.read().unwrap().data_ref().to_vec() - } -} diff --git a/src/bitvec.rs b/src/bitvec.rs deleted file mode 100644 index 1ad7751..0000000 --- a/src/bitvec.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::sync::{Arc, RwLock}; - -#[derive(uniffi::Object)] -pub struct BitVec { - pub(crate) actual: RwLock, -} - -impl BitVec { - fn internal_new(actual: servicepoint::BitVec) -> Arc { - Arc::new(Self { - actual: RwLock::new(actual), - }) - } -} - -#[uniffi::export] -impl BitVec { - #[uniffi::constructor] - pub fn new(size: u64) -> Arc { - Self::internal_new(servicepoint::BitVec::repeat(false, size as usize)) - } - #[uniffi::constructor] - pub fn load(data: Vec) -> Arc { - Self::internal_new(servicepoint::BitVec::from_slice(&data)) - } - - #[uniffi::constructor] - pub fn clone(other: &Arc) -> Arc { - Self::internal_new(other.actual.read().unwrap().clone()) - } - - pub fn set(&self, index: u64, value: bool) { - self.actual.write().unwrap().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) - } - - pub fn fill(&self, value: bool) { - self.actual.write().unwrap().fill(value) - } - - pub fn len(&self) -> u64 { - self.actual.read().unwrap().len() as u64 - } - - pub fn equals(&self, other: &BitVec) -> bool { - let a = self.actual.read().unwrap(); - let b = other.actual.read().unwrap(); - *a == *b - } - - pub fn copy_raw(&self) -> Vec { - self.actual.read().unwrap().clone().into_vec() - } -} diff --git a/src/brightness.rs b/src/brightness.rs new file mode 100644 index 0000000..8efba1e --- /dev/null +++ b/src/brightness.rs @@ -0,0 +1,21 @@ +use crate::errors::ServicePointError; +use crate::UniffiCustomTypeConverter; +use servicepoint::Brightness; + +uniffi::custom_type!(Brightness, u8); + +impl UniffiCustomTypeConverter for Brightness { + type Builtin = u8; + + fn into_custom(val: Self::Builtin) -> uniffi::Result + where + Self: Sized, + { + Ok(Brightness::try_from(val) + .map_err(|value| ServicePointError::InvalidBrightness { value })?) + } + + fn from_custom(obj: Self) -> Self::Builtin { + obj.into() + } +} diff --git a/src/brightness_grid.rs b/src/brightness_grid.rs deleted file mode 100644 index afa0e3f..0000000 --- a/src/brightness_grid.rs +++ /dev/null @@ -1,86 +0,0 @@ -use servicepoint::{Brightness, DataRef, Grid}; -use std::sync::{Arc, RwLock}; - -#[derive(uniffi::Object)] -pub struct BrightnessGrid { - pub(crate) actual: RwLock, -} - -impl BrightnessGrid { - fn internal_new(actual: servicepoint::BrightnessGrid) -> Arc { - Arc::new(Self { - actual: RwLock::new(actual), - }) - } -} - -#[uniffi::export] -impl BrightnessGrid { - #[uniffi::constructor] - pub fn new(width: u64, height: u64) -> Arc { - Self::internal_new(servicepoint::BrightnessGrid::new( - width as usize, - height as usize, - )) - } - - #[uniffi::constructor] - pub fn load(width: u64, height: u64, data: Vec) -> Arc { - Self::internal_new(servicepoint::BrightnessGrid::saturating_load( - width as usize, - height as usize, - &data, - )) - } - - #[uniffi::constructor] - pub fn clone(other: &Arc) -> Arc { - Self::internal_new(other.actual.read().unwrap().clone()) - } - - pub fn set(&self, x: u64, y: u64, value: u8) { - self.actual.write().unwrap().set( - x as usize, - y as usize, - Brightness::saturating_from(value), - ) - } - - pub fn get(&self, x: u64, y: u64) -> u8 { - self.actual - .read() - .unwrap() - .get(x as usize, y as usize) - .into() - } - - pub fn fill(&self, value: u8) { - self.actual - .write() - .unwrap() - .fill(Brightness::saturating_from(value)) - } - pub fn width(&self) -> u64 { - self.actual.read().unwrap().width() as u64 - } - - pub fn height(&self) -> u64 { - self.actual.read().unwrap().height() as u64 - } - - pub fn equals(&self, other: &BrightnessGrid) -> bool { - let a = self.actual.read().unwrap(); - let b = other.actual.read().unwrap(); - *a == *b - } - - pub fn copy_raw(&self) -> Vec { - self.actual - .read() - .unwrap() - .data_ref() - .iter() - .map(u8::from) - .collect() - } -} diff --git a/src/char_grid.rs b/src/char_grid.rs deleted file mode 100644 index e5d59a8..0000000 --- a/src/char_grid.rs +++ /dev/null @@ -1,169 +0,0 @@ -use crate::cp437_grid::Cp437Grid; -use servicepoint::{Grid, SetValueSeriesError}; -use std::convert::Into; -use std::sync::{Arc, RwLock}; - -#[derive(uniffi::Object)] -pub struct CharGrid { - pub(crate) actual: RwLock, -} - -#[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] - pub fn new(width: u64, height: u64) -> Arc { - Self::internal_new(servicepoint::CharGrid::new( - width as usize, - height as usize, - )) - } - - #[uniffi::constructor] - pub fn load(data: String) -> Arc { - Self::internal_new(servicepoint::CharGrid::from(&*data)) - } - - #[uniffi::constructor] - pub fn clone(other: &Arc) -> Arc { - Self::internal_new(other.actual.read().unwrap().clone()) - } - - pub fn set( - &self, - x: u64, - y: u64, - value: String, - ) -> Result<(), CharGridError> { - let value = Self::str_to_char(value)?; - self.actual - .write() - .unwrap() - .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() - } - - pub fn fill(&self, value: String) -> Result<(), CharGridError> { - let value = Self::str_to_char(value)?; - self.actual.write().unwrap().fill(value); - Ok(()) - } - - pub fn width(&self) -> u64 { - self.actual.read().unwrap().width() as u64 - } - - pub fn height(&self) -> u64 { - self.actual.read().unwrap().height() as u64 - } - - pub fn equals(&self, other: &CharGrid) -> bool { - let a = self.actual.read().unwrap(); - let b = other.actual.read().unwrap(); - *a == *b - } - - pub fn as_string(&self) -> String { - let grid = self.actual.read().unwrap(); - String::from(&*grid) - } - - pub fn set_row(&self, y: u64, row: String) -> Result<(), CharGridError> { - self.actual - .write() - .unwrap() - .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() - .set_row(x as usize, &col.chars().collect::>()) - .map_err(CharGridError::from) - } - - pub fn get_row(&self, y: u64) -> Result { - self.actual - .read() - .unwrap() - .get_row(y as usize) - .map(String::from_iter) - .ok_or(CharGridError::OutOfBounds { - index: y, - size: self.height(), - }) - } - - pub fn get_col(&self, x: u64) -> Result { - self.actual - .read() - .unwrap() - .get_col(x as usize) - .map(String::from_iter) - .ok_or(CharGridError::OutOfBounds { - index: x, - size: self.width(), - }) - } - - pub fn to_cp437(&self) -> Arc { - Cp437Grid::internal_new(servicepoint::Cp437Grid::from( - &*self.actual.read().unwrap(), - )) - } -} - -impl CharGrid { - pub(crate) fn internal_new(actual: servicepoint::CharGrid) -> Arc { - Arc::new(Self { - actual: RwLock::new(actual), - }) - } - - fn str_to_char(value: String) -> Result { - if value.len() != 1 { - return Err(CharGridError::StringNotOneChar { value }); - } - - let value = value.chars().nth(0).unwrap(); - Ok(value) - } -} - -impl From for CharGridError { - fn from(e: SetValueSeriesError) -> Self { - match e { - SetValueSeriesError::OutOfBounds { index, size } => { - CharGridError::OutOfBounds { - index: index as u64, - size: size as u64, - } - } - SetValueSeriesError::InvalidLength { actual, expected } => { - CharGridError::InvalidSeriesLength { - actual: actual as u64, - expected: expected as u64, - } - } - } - } -} diff --git a/src/command.rs b/src/command.rs deleted file mode 100644 index bb479ae..0000000 --- a/src/command.rs +++ /dev/null @@ -1,175 +0,0 @@ -use crate::bitmap::Bitmap; -use crate::bitvec::BitVec; -use crate::brightness_grid::BrightnessGrid; -use crate::char_grid::CharGrid; -use crate::compression_code::CompressionCode; -use crate::cp437_grid::Cp437Grid; -use crate::errors::ServicePointError; -use servicepoint::Origin; -use std::sync::Arc; - -#[derive(uniffi::Object)] -pub struct Command { - pub(crate) actual: servicepoint::Command, -} - -impl Command { - fn internal_new(actual: servicepoint::Command) -> Arc { - Arc::new(Command { actual }) - } -} - -#[uniffi::export] -impl Command { - #[uniffi::constructor] - pub fn clear() -> Arc { - Self::internal_new(servicepoint::Command::Clear) - } - - #[uniffi::constructor] - pub fn brightness(brightness: u8) -> Result, ServicePointError> { - servicepoint::Brightness::try_from(brightness) - .map_err(move |value| ServicePointError::InvalidBrightness { - value, - }) - .map(servicepoint::Command::Brightness) - .map(Self::internal_new) - } - - #[uniffi::constructor] - pub fn fade_out() -> Arc { - Self::internal_new(servicepoint::Command::FadeOut) - } - - #[uniffi::constructor] - pub fn hard_reset() -> Arc { - Self::internal_new(servicepoint::Command::HardReset) - } - - #[uniffi::constructor] - pub fn bitmap_linear_win( - offset_x: u64, - offset_y: u64, - bitmap: &Arc, - compression: CompressionCode, - ) -> Arc { - let origin = Origin::new(offset_x as usize, offset_y as usize); - let bitmap = bitmap.actual.read().unwrap().clone(); - let actual = servicepoint::Command::BitmapLinearWin( - origin, - bitmap, - servicepoint::CompressionCode::try_from(compression as u16) - .unwrap(), - ); - Self::internal_new(actual) - } - - #[uniffi::constructor] - pub fn char_brightness( - offset_x: u64, - offset_y: u64, - grid: &Arc, - ) -> Arc { - let origin = Origin::new(offset_x as usize, offset_y as usize); - let grid = grid.actual.read().unwrap().clone(); - let actual = servicepoint::Command::CharBrightness(origin, grid); - Self::internal_new(actual) - } - - #[uniffi::constructor] - pub fn bitmap_linear( - offset: u64, - bitmap: &Arc, - compression: CompressionCode, - ) -> Arc { - let bitmap = bitmap.actual.read().unwrap().clone(); - let actual = servicepoint::Command::BitmapLinear( - offset as usize, - bitmap, - servicepoint::CompressionCode::try_from(compression as u16) - .unwrap(), - ); - Self::internal_new(actual) - } - - #[uniffi::constructor] - pub fn bitmap_linear_and( - offset: u64, - bitmap: &Arc, - compression: CompressionCode, - ) -> Arc { - let bitmap = bitmap.actual.read().unwrap().clone(); - let actual = servicepoint::Command::BitmapLinearAnd( - offset as usize, - bitmap, - servicepoint::CompressionCode::try_from(compression as u16) - .unwrap(), - ); - Self::internal_new(actual) - } - - #[uniffi::constructor] - pub fn bitmap_linear_or( - offset: u64, - bitmap: &Arc, - compression: CompressionCode, - ) -> Arc { - let bitmap = bitmap.actual.read().unwrap().clone(); - let actual = servicepoint::Command::BitmapLinearOr( - offset as usize, - bitmap, - servicepoint::CompressionCode::try_from(compression as u16) - .unwrap(), - ); - Self::internal_new(actual) - } - - #[uniffi::constructor] - pub fn bitmap_linear_xor( - offset: u64, - bitmap: &Arc, - compression: CompressionCode, - ) -> Arc { - let bitmap = bitmap.actual.read().unwrap().clone(); - let actual = servicepoint::Command::BitmapLinearXor( - offset as usize, - bitmap, - servicepoint::CompressionCode::try_from(compression as u16) - .unwrap(), - ); - Self::internal_new(actual) - } - - #[uniffi::constructor] - pub fn cp437_data( - offset_x: u64, - offset_y: u64, - grid: &Arc, - ) -> Arc { - let origin = Origin::new(offset_x as usize, offset_y as usize); - let grid = grid.actual.read().unwrap().clone(); - let actual = servicepoint::Command::Cp437Data(origin, grid); - Self::internal_new(actual) - } - - #[uniffi::constructor] - pub fn utf8_data( - offset_x: u64, - offset_y: u64, - grid: &Arc, - ) -> Arc { - let origin = Origin::new(offset_x as usize, offset_y as usize); - let grid = grid.actual.read().unwrap().clone(); - let actual = servicepoint::Command::Utf8Data(origin, grid); - Self::internal_new(actual) - } - - #[uniffi::constructor] - pub fn clone(other: &Arc) -> Arc { - Self::internal_new(other.actual.clone()) - } - - pub fn equals(&self, other: &Command) -> bool { - self.actual == other.actual - } -} diff --git a/src/commands/bitmap.rs b/src/commands/bitmap.rs new file mode 100644 index 0000000..062f3dc --- /dev/null +++ b/src/commands/bitmap.rs @@ -0,0 +1,31 @@ +use crate::{ + commands::wrap_command, compression_code::CompressionCode, + containers::bitmap::Bitmap, macros::wrap_object_attr_wrapped, +}; +use servicepoint::Origin; +use std::sync::Arc; + +wrap_command!(BitmapCommand); + +wrap_object_attr_wrapped!(BitmapCommand, bitmap, Bitmap); + +#[uniffi::export] +impl BitmapCommand { + #[uniffi::constructor] + pub fn new( + offset_x: u64, + offset_y: u64, + bitmap: &Arc, + compression: CompressionCode, + ) -> Arc { + let origin = Origin::new(offset_x as usize, offset_y as usize); + let bitmap = bitmap.read().clone(); + let compression = compression.into(); + let actual = servicepoint::BitmapCommand { + origin, + bitmap, + compression, + }; + Self::internal_new(actual) + } +} diff --git a/src/commands/bitvec.rs b/src/commands/bitvec.rs new file mode 100644 index 0000000..537f95f --- /dev/null +++ b/src/commands/bitvec.rs @@ -0,0 +1,52 @@ +use crate::{ + commands::wrap_command, compression_code::CompressionCode, + containers::bitvec::BitVec, macros::wrap_object_attr_wrapped, +}; +use std::sync::Arc; + +wrap_command!(BitVecCommand); +wrap_object_attr_wrapped!(BitVecCommand, bitvec, BitVec); + +#[uniffi::export] +impl BitVecCommand { + #[uniffi::constructor] + pub fn new( + offset: u64, + bitvec: &Arc, + compression: CompressionCode, + operation: BinaryOperation, + ) -> Arc { + let offset = offset as usize; + let bitvec = bitvec.read().clone(); + let compression = compression.into(); + let operation = operation.into(); + let actual = servicepoint::BitVecCommand { + offset, + bitvec, + compression, + operation, + }; + Self::internal_new(actual) + } +} + +#[derive(uniffi::Enum)] +pub enum BinaryOperation { + Overwrite, + And, + Or, + Xor, +} + +impl From for servicepoint::BinaryOperation { + fn from(op: BinaryOperation) -> Self { + match op { + BinaryOperation::Overwrite => { + servicepoint::BinaryOperation::Overwrite + } + BinaryOperation::And => servicepoint::BinaryOperation::And, + BinaryOperation::Or => servicepoint::BinaryOperation::Or, + BinaryOperation::Xor => servicepoint::BinaryOperation::Xor, + } + } +} diff --git a/src/commands/brightness_grid.rs b/src/commands/brightness_grid.rs new file mode 100644 index 0000000..d48d8ee --- /dev/null +++ b/src/commands/brightness_grid.rs @@ -0,0 +1,24 @@ +use crate::{ + commands::wrap_command, containers::brightness_grid::BrightnessGrid, + macros::wrap_object_attr_wrapped, +}; +use servicepoint::Origin; +use std::sync::Arc; + +wrap_command!(BrightnessGridCommand); +wrap_object_attr_wrapped!(BrightnessGridCommand, grid, BrightnessGrid); + +#[uniffi::export] +impl BrightnessGridCommand { + #[uniffi::constructor] + pub fn new( + offset_x: u64, + offset_y: u64, + grid: &Arc, + ) -> Arc { + let origin = Origin::new(offset_x as usize, offset_y as usize); + let grid = grid.read().clone(); + let actual = servicepoint::BrightnessGridCommand { origin, grid }; + Self::internal_new(actual) + } +} diff --git a/src/commands/cc_only.rs b/src/commands/cc_only.rs new file mode 100644 index 0000000..576f1e2 --- /dev/null +++ b/src/commands/cc_only.rs @@ -0,0 +1,19 @@ +use std::sync::Arc; + +macro_rules! command_code_only_command { + ($command_struct:ident) => { + crate::commands::wrap_command!($command_struct); + + #[uniffi::export] + impl $command_struct { + #[uniffi::constructor] + pub fn new() -> Arc { + Self::internal_new(::servicepoint::$command_struct) + } + } + }; +} + +command_code_only_command!(ClearCommand); +command_code_only_command!(HardResetCommand); +command_code_only_command!(FadeOutCommand); diff --git a/src/commands/char_grid.rs b/src/commands/char_grid.rs new file mode 100644 index 0000000..94da405 --- /dev/null +++ b/src/commands/char_grid.rs @@ -0,0 +1,24 @@ +use crate::{ + commands::wrap_command, containers::char_grid::CharGrid, + macros::wrap_object_attr_wrapped, +}; +use servicepoint::Origin; +use std::sync::Arc; + +wrap_command!(CharGridCommand); +wrap_object_attr_wrapped!(CharGridCommand, grid, CharGrid); + +#[uniffi::export] +impl CharGridCommand { + #[uniffi::constructor] + pub fn new( + offset_x: u64, + offset_y: u64, + grid: &Arc, + ) -> Arc { + let origin = Origin::new(offset_x as usize, offset_y as usize); + let grid = grid.read().clone(); + let actual = servicepoint::CharGridCommand { origin, grid }; + Self::internal_new(actual) + } +} diff --git a/src/commands/cp437.rs b/src/commands/cp437.rs new file mode 100644 index 0000000..59d55a6 --- /dev/null +++ b/src/commands/cp437.rs @@ -0,0 +1,24 @@ +use crate::{ + commands::wrap_command, containers::cp437_grid::Cp437Grid, + macros::wrap_object_attr_wrapped, +}; +use servicepoint::Origin; +use std::sync::Arc; + +wrap_command!(Cp437GridCommand); +wrap_object_attr_wrapped!(Cp437GridCommand, grid, Cp437Grid); + +#[uniffi::export] +impl Cp437GridCommand { + #[uniffi::constructor] + pub fn new( + offset_x: u64, + offset_y: u64, + grid: &Arc, + ) -> Arc { + let origin = Origin::new(offset_x as usize, offset_y as usize); + let grid = grid.read().clone(); + let actual = servicepoint::Cp437GridCommand { origin, grid }; + Self::internal_new(actual) + } +} diff --git a/src/commands/global_brightness.rs b/src/commands/global_brightness.rs new file mode 100644 index 0000000..5d626e5 --- /dev/null +++ b/src/commands/global_brightness.rs @@ -0,0 +1,15 @@ +use crate::commands::wrap_command; +use servicepoint::Brightness; +use std::sync::Arc; + +wrap_command!(GlobalBrightnessCommand); + +#[uniffi::export] +impl GlobalBrightnessCommand { + #[uniffi::constructor] + pub fn new(brightness: Brightness) -> Arc { + Self::internal_new(servicepoint::GlobalBrightnessCommand::from( + brightness, + )) + } +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs new file mode 100644 index 0000000..0773b18 --- /dev/null +++ b/src/commands/mod.rs @@ -0,0 +1,66 @@ +mod bitmap; +mod bitvec; +mod brightness_grid; +mod cc_only; +mod char_grid; +mod cp437; +mod global_brightness; + +use std::sync::Arc; + +pub use bitmap::BitmapCommand; +pub use bitvec::{BinaryOperation, BitVecCommand}; +pub use brightness_grid::BrightnessGridCommand; +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, + ) -> Result, crate::errors::ServicePointError>; +} + +macro_rules! wrap_command { + ($command:ident) => { + crate::macros::wrap_object!($command); + + #[uniffi::export] + impl $command { + fn as_packet( + &self, + ) -> Result< + Arc, + crate::errors::ServicePointError, + > { + self.read() + .clone() + .try_into() + .map(crate::packet::Packet::internal_new) + .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/compression_code.rs b/src/compression_code.rs index 078230a..bf530f1 100644 --- a/src/compression_code.rs +++ b/src/compression_code.rs @@ -12,3 +12,31 @@ pub enum CompressionCode { /// compress using Zstandard Zstd = 0x7a73, } + +impl From for CompressionCode { + fn from(value: servicepoint::CompressionCode) -> Self { + 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 { + 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/connection.rs b/src/connection.rs index 6ba4e07..5b9ed52 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,36 +1,39 @@ -use std::sync::Arc; - -use crate::command::Command; -use crate::errors::ServicePointError; +use crate::commands::Command; +use crate::{errors::ServicePointError, packet::Packet}; +use servicepoint::UdpSocketExt; +use std::{net::UdpSocket, sync::Arc}; #[derive(uniffi::Object)] pub struct Connection { - actual: servicepoint::Connection, + actual: UdpSocket, } #[uniffi::export] impl Connection { #[uniffi::constructor] pub fn new(host: String) -> Result, ServicePointError> { - servicepoint::Connection::open(host) + UdpSocket::bind_connect(host) .map(|actual| Arc::new(Connection { actual })) .map_err(|err| ServicePointError::IoError { error: err.to_string(), }) } - #[uniffi::constructor] - pub fn new_fake() -> Arc { - Arc::new(Self { - actual: servicepoint::Connection::Fake, - }) + pub fn send_packet( + &self, + command: Arc, + ) -> Result<(), ServicePointError> { + self.actual + .send_command(command.read().clone()) + .ok_or_else(|| ServicePointError::IoError { + error: "send failed".to_string(), + }) } - pub fn send(&self, command: Arc) -> Result<(), ServicePointError> { - self.actual.send(command.actual.clone()).map_err(|err| { - ServicePointError::IoError { - error: format!("{err:?}"), - } - }) + 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 new file mode 100644 index 0000000..1418e5e --- /dev/null +++ b/src/containers/bitmap.rs @@ -0,0 +1,38 @@ +use crate::{ + containers::{wrap_get_set_fill_2d, wrap_width_height}, + macros::wrap_object, +}; +use servicepoint::Grid; +use std::{ops::Deref, sync::Arc}; + +wrap_object!(Bitmap); +wrap_width_height!(Bitmap); +wrap_get_set_fill_2d!(Bitmap, bool); + +#[uniffi::export] +impl Bitmap { + #[uniffi::constructor] + pub fn new(width: u64, height: u64) -> Arc { + Self::internal_new( + servicepoint::Bitmap::new(width as usize, height as usize).unwrap(), + ) + } + + #[uniffi::constructor] + pub fn new_max_sized() -> Arc { + Self::internal_new(servicepoint::Bitmap::max_sized()) + } + + #[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 copy_raw(&self) -> Vec { + self.read().deref().into() + } +} diff --git a/src/containers/bitvec.rs b/src/containers/bitvec.rs new file mode 100644 index 0000000..cd2c87d --- /dev/null +++ b/src/containers/bitvec.rs @@ -0,0 +1,39 @@ +use crate::macros::wrap_object; +use std::sync::Arc; + +wrap_object!(DisplayBitVec, BitVec); + +#[uniffi::export] +impl BitVec { + #[uniffi::constructor] + pub fn new(size: u64) -> Arc { + Self::internal_new(servicepoint::DisplayBitVec::repeat( + false, + size as usize, + )) + } + #[uniffi::constructor] + pub fn load(data: Vec) -> Arc { + Self::internal_new(servicepoint::DisplayBitVec::from_slice(&data)) + } + + pub fn set(&self, index: u64, value: bool) { + self.write().set(index as usize, value) + } + + pub fn get(&self, index: u64) -> bool { + self.read().get(index as usize).is_some_and(move |bit| *bit) + } + + pub fn fill(&self, value: bool) { + self.write().fill(value) + } + + pub fn len(&self) -> u64 { + self.read().len() as u64 + } + + 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 new file mode 100644 index 0000000..6bb3cbc --- /dev/null +++ b/src/containers/brightness_grid.rs @@ -0,0 +1,37 @@ +use crate::{ + containers::{wrap_get_set_fill_2d, wrap_width_height}, + macros::wrap_object, +}; +use servicepoint::{Brightness, Grid}; +use std::{ops::Deref, sync::Arc}; + +wrap_object!(BrightnessGrid); +wrap_width_height!(BrightnessGrid); +wrap_get_set_fill_2d!(BrightnessGrid, Brightness); + +#[uniffi::export] +impl BrightnessGrid { + #[uniffi::constructor] + pub fn new(width: u64, height: u64) -> Arc { + Self::internal_new(servicepoint::BrightnessGrid::new( + width as usize, + height as usize, + )) + } + + #[uniffi::constructor] + pub fn load(width: u64, height: u64, data: Vec) -> Arc { + Self::internal_new( + servicepoint::BrightnessGrid::saturating_load( + width as usize, + height as usize, + &data, + ) + .unwrap(), + ) + } + + pub fn copy_raw(&self) -> Vec { + self.read().deref().into() + } +} diff --git a/src/containers/char_grid.rs b/src/containers/char_grid.rs new file mode 100644 index 0000000..28712be --- /dev/null +++ b/src/containers/char_grid.rs @@ -0,0 +1,123 @@ +use crate::{ + containers::{cp437_grid::Cp437Grid, wrap_width_height}, + errors::ServicePointError, + macros::wrap_object, +}; +use servicepoint::{Grid, SetValueSeriesError}; +use std::sync::Arc; + +wrap_object!(CharGrid); +wrap_width_height!(CharGrid); + +#[uniffi::export] +impl CharGrid { + #[uniffi::constructor] + pub fn new(width: u64, height: u64) -> Arc { + Self::internal_new(servicepoint::CharGrid::new( + width as usize, + height as usize, + )) + } + + #[uniffi::constructor] + pub fn load(data: String) -> Arc { + Self::internal_new(servicepoint::CharGrid::from(&*data)) + } + + pub fn set( + &self, + x: u64, + y: u64, + value: String, + ) -> Result<(), ServicePointError> { + let value = Self::str_to_char(value)?; + 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) -> 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<(), ServicePointError> { + let value = Self::str_to_char(value)?; + self.write().fill(value); + Ok(()) + } + + pub fn as_string(&self) -> String { + let grid = self.read(); + String::from(&*grid) + } + + pub fn set_row( + &self, + y: u64, + row: String, + ) -> Result<(), ServicePointError> { + self.write() + .set_row(y as usize, &row.chars().collect::>()) + .map_err(ServicePointError::from) + } + + pub fn set_col( + &self, + x: u64, + col: String, + ) -> Result<(), ServicePointError> { + self.write() + .set_row(x as usize, &col.chars().collect::>()) + .map_err(ServicePointError::from) + } + + pub fn get_row(&self, y: u64) -> Result { + self.read() + .get_row(y as usize) + .map(String::from_iter) + .ok_or(ServicePointError::OutOfBounds) + } + + pub fn get_col(&self, x: u64) -> Result { + self.read() + .get_col(x as usize) + .map(String::from_iter) + .ok_or(ServicePointError::OutOfBounds) + } + + pub fn to_cp437(&self) -> Arc { + Cp437Grid::internal_new(servicepoint::Cp437Grid::from(&*self.read())) + } +} + +impl CharGrid { + fn str_to_char(value: String) -> Result { + if value.len() != 1 { + return Err(ServicePointError::StringNotOneChar { value }); + } + + let value = value.chars().nth(0).unwrap(); + Ok(value) + } +} + +impl From for ServicePointError { + fn from(e: SetValueSeriesError) -> Self { + match e { + SetValueSeriesError::OutOfBounds { .. } => { + ServicePointError::OutOfBounds + } + SetValueSeriesError::InvalidLength { actual, expected } => { + ServicePointError::InvalidSeriesLength { + actual: actual as u64, + expected: expected as u64, + } + } + } + } +} diff --git a/src/containers/cp437_grid.rs b/src/containers/cp437_grid.rs new file mode 100644 index 0000000..fdd25e0 --- /dev/null +++ b/src/containers/cp437_grid.rs @@ -0,0 +1,42 @@ +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}; + +wrap_object!(Cp437Grid); +wrap_width_height!(Cp437Grid); +wrap_get_set_fill_2d!(Cp437Grid, u8); + +#[uniffi::export] +impl Cp437Grid { + #[uniffi::constructor] + pub fn new(width: u64, height: u64) -> Arc { + Self::internal_new(servicepoint::Cp437Grid::new( + width as usize, + height as usize, + )) + } + + #[uniffi::constructor] + pub fn load(width: u64, height: u64, data: Vec) -> Arc { + Self::internal_new( + servicepoint::Cp437Grid::load( + width as usize, + height as usize, + &data, + ) + .unwrap(), + ) + } + + pub fn copy_raw(&self) -> Vec { + self.read().deref().into() + } + + pub fn to_utf8(&self) -> Arc { + CharGrid::internal_new(servicepoint::CharGrid::from(&*self.read())) + } +} diff --git a/src/containers/mod.rs b/src/containers/mod.rs new file mode 100644 index 0000000..f1d4880 --- /dev/null +++ b/src/containers/mod.rs @@ -0,0 +1,46 @@ +pub mod bitmap; +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/cp437_grid.rs b/src/cp437_grid.rs deleted file mode 100644 index b201238..0000000 --- a/src/cp437_grid.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::char_grid::CharGrid; -use servicepoint::{DataRef, Grid}; -use std::sync::{Arc, RwLock}; - -#[derive(uniffi::Object)] -pub struct Cp437Grid { - pub(crate) actual: RwLock, -} - -impl Cp437Grid { - pub(crate) fn internal_new(actual: servicepoint::Cp437Grid) -> Arc { - Arc::new(Self { - actual: RwLock::new(actual), - }) - } -} - -#[uniffi::export] -impl Cp437Grid { - #[uniffi::constructor] - pub fn new(width: u64, height: u64) -> Arc { - Self::internal_new(servicepoint::Cp437Grid::new( - width as usize, - height as usize, - )) - } - - #[uniffi::constructor] - pub fn load(width: u64, height: u64, data: Vec) -> Arc { - Self::internal_new(servicepoint::Cp437Grid::load( - width as usize, - height as usize, - &data, - )) - } - - #[uniffi::constructor] - pub fn clone(other: &Arc) -> Arc { - Self::internal_new(other.actual.read().unwrap().clone()) - } - - pub fn set(&self, x: u64, y: u64, value: u8) { - self.actual - .write() - .unwrap() - .set(x as usize, y as usize, value) - } - - pub fn get(&self, x: u64, y: u64) -> u8 { - self.actual.read().unwrap().get(x as usize, y as usize) - } - - pub fn fill(&self, value: u8) { - self.actual.write().unwrap().fill(value) - } - pub fn width(&self) -> u64 { - self.actual.read().unwrap().width() as u64 - } - - pub fn height(&self) -> u64 { - self.actual.read().unwrap().height() as u64 - } - - pub fn equals(&self, other: &Cp437Grid) -> bool { - let a = self.actual.read().unwrap(); - let b = other.actual.read().unwrap(); - *a == *b - } - - pub fn copy_raw(&self) -> Vec { - self.actual.read().unwrap().data_ref().to_vec() - } - - pub fn to_utf8(&self) -> Arc { - CharGrid::internal_new(servicepoint::CharGrid::from( - &*self.actual.read().unwrap(), - )) - } -} diff --git a/src/errors.rs b/src/errors.rs index 9c28f5f..f234278 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -4,4 +4,12 @@ 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, + #[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/lib.rs b/src/lib.rs index 2ecad45..082ab6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,11 @@ uniffi::setup_scaffolding!(); -mod bitmap; -mod bitvec; -mod brightness_grid; -mod char_grid; -mod command; -mod compression_code; -mod connection; -mod constants; -mod cp437_grid; -mod errors; +pub mod brightness; +pub mod commands; +pub mod compression_code; +pub mod connection; +pub mod constants; +pub mod containers; +pub mod errors; +pub mod macros; +mod packet; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..140b42c --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,128 @@ +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>, + } + + #[allow(unused)] + impl $new_t { + pub(crate) fn internal_new( + actual: ::servicepoint::$orig_t, + ) -> ::std::sync::Arc { + ::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( + &self, + ) -> ::std::sync::RwLockReadGuard<::servicepoint::$orig_t> { + self.actual.read().unwrap() + } + + pub(crate) fn write( + &self, + ) -> ::std::sync::RwLockWriteGuard<::servicepoint::$orig_t> { + self.actual.write().unwrap() + } + } + + #[uniffi::export] + impl $new_t { + #[uniffi::constructor] + pub fn clone( + other: &::std::sync::Arc, + ) -> ::std::sync::Arc { + 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) => { + crate::macros::wrap_object!($t, $t); + }; +} + +macro_rules! wrap_object_attr_wrapped_get { + ($object:ident, $attr_name:ident, $attr_type:ident, $fun_name:ident) => { + #[uniffi::export] + 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, []); + } + }; +} + +macro_rules! wrap_object_attr_wrapped_set { + ($object:ident, $attr_name:ident, $attr_type:ident, $fun_name:ident) => { + #[uniffi::export] + 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, []); + } + }; +} + +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 new file mode 100644 index 0000000..bdfd0a8 --- /dev/null +++ b/src/packet.rs @@ -0,0 +1,13 @@ +use crate::macros::{wrap_object, wrap_object_attr_wrapped}; + +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()) + } +}