Compare commits

..

12 commits
main ... next

Author SHA1 Message Date
Vinzenz Schroeter ecb4f51997 partially fix tests 2025-06-16 16:37:20 +02:00
Vinzenz Schroeter 0894b15c65 export some builtin traits,
brightness conversion fails for invalid values,

macros for wrapping attrs
2025-06-16 15:01:53 +02:00
Vinzenz Schroeter b218bd6474 create separate types per command 2025-06-16 11:33:40 +02:00
Vinzenz Schroeter 635fef0244 move command to module, first separate types 2025-06-13 11:47:23 +02:00
Vinzenz Schroeter cee4937270 move containers to module 2025-06-13 11:45:11 +02:00
Vinzenz Schroeter 27d71cefe6 update to nixos 25.05 2025-06-13 11:05:31 +02:00
Vinzenz Schroeter 8f03010944 update servicepoint, simplify copy_raw 2025-06-13 10:17:59 +02:00
Vinzenz Schroeter 7fe5ef07a8 add get set fill macro 2025-06-13 09:52:07 +02:00
Vinzenz Schroeter 0b3f243ffa add width and height macro 2025-06-13 01:27:57 +02:00
Vinzenz Schroeter fda2b9419d add clone to macro 2025-06-13 01:13:51 +02:00
Vinzenz Schroeter 88f7696dbd declare wrapper types with macro 2025-06-13 01:09:31 +02:00
Vinzenz Schroeter 022106e2db update servicepoint library 2025-05-04 18:55:19 +02:00
31 changed files with 871 additions and 726 deletions

95
Cargo.lock generated
View file

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "adler2" name = "adler2"
@ -209,9 +209,9 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]] [[package]]
name = "goblin" name = "goblin"
version = "0.6.1" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68" checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47"
dependencies = [ dependencies = [
"log", "log",
"plain", "plain",
@ -220,9 +220,9 @@ dependencies = [
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.1" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "itoa" name = "itoa"
@ -304,12 +304,6 @@ version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "oneshot-uniffi"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c"
[[package]] [[package]]
name = "paste" name = "paste"
version = "1.0.15" version = "1.0.15"
@ -370,18 +364,18 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]] [[package]]
name = "scroll" name = "scroll"
version = "0.11.0" version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6"
dependencies = [ dependencies = [
"scroll_derive", "scroll_derive",
] ]
[[package]] [[package]]
name = "scroll_derive" name = "scroll_derive"
version = "0.11.1" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -431,9 +425,8 @@ dependencies = [
[[package]] [[package]]
name = "servicepoint" name = "servicepoint"
version = "0.13.1" version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint.git?branch=next#5b6f88b1682925b7669b25a7fb08806c4009bbfd"
checksum = "93b52049be55a15fe37c13249d7f96aa8a5de56e1a41838e74a822ee8316a0c4"
dependencies = [ dependencies = [
"bitvec", "bitvec",
"bzip2", "bzip2",
@ -447,8 +440,9 @@ dependencies = [
[[package]] [[package]]
name = "servicepoint_binding_uniffi" name = "servicepoint_binding_uniffi"
version = "0.13.1" version = "0.15.0"
dependencies = [ dependencies = [
"paste",
"servicepoint", "servicepoint",
"thiserror 2.0.11", "thiserror 2.0.11",
"uniffi", "uniffi",
@ -466,6 +460,12 @@ version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "smawk"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
@ -489,6 +489,15 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "textwrap"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
dependencies = [
"smawk",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.69" version = "1.0.69"
@ -552,11 +561,13 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]] [[package]]
name = "uniffi" name = "uniffi"
version = "0.25.3" version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21345172d31092fd48c47fd56c53d4ae9e41c4b1f559fb8c38c1ab1685fd919f" checksum = "4cb08c58c7ed7033150132febe696bef553f891b1ede57424b40d87a89e3c170"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cargo_metadata",
"uniffi_bindgen",
"uniffi_build", "uniffi_build",
"uniffi_core", "uniffi_core",
"uniffi_macros", "uniffi_macros",
@ -564,9 +575,9 @@ dependencies = [
[[package]] [[package]]
name = "uniffi_bindgen" name = "uniffi_bindgen"
version = "0.25.3" version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd992f2929a053829d5875af1eff2ee3d7a7001cb3b9a46cc7895f2caede6940" checksum = "cade167af943e189a55020eda2c314681e223f1e42aca7c4e52614c2b627698f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"askama", "askama",
@ -579,17 +590,17 @@ dependencies = [
"once_cell", "once_cell",
"paste", "paste",
"serde", "serde",
"textwrap",
"toml", "toml",
"uniffi_meta", "uniffi_meta",
"uniffi_testing",
"uniffi_udl", "uniffi_udl",
] ]
[[package]] [[package]]
name = "uniffi_build" name = "uniffi_build"
version = "0.25.3" version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "001964dd3682d600084b3aaf75acf9c3426699bc27b65e96bb32d175a31c74e9" checksum = "4c7cf32576e08104b7dc2a6a5d815f37616e66c6866c2a639fe16e6d2286b75b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"camino", "camino",
@ -598,9 +609,9 @@ dependencies = [
[[package]] [[package]]
name = "uniffi_checksum_derive" name = "uniffi_checksum_derive"
version = "0.25.3" version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55137c122f712d9330fd985d66fa61bdc381752e89c35708c13ce63049a3002c" checksum = "802d2051a700e3ec894c79f80d2705b69d85844dafbbe5d1a92776f8f48b563a"
dependencies = [ dependencies = [
"quote", "quote",
"syn", "syn",
@ -608,25 +619,23 @@ dependencies = [
[[package]] [[package]]
name = "uniffi_core" name = "uniffi_core"
version = "0.25.3" version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6121a127a3af1665cd90d12dd2b3683c2643c5103281d0fed5838324ca1fad5b" checksum = "bc7687007d2546c454d8ae609b105daceb88175477dac280707ad6d95bcd6f1f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
"camino",
"log", "log",
"once_cell", "once_cell",
"oneshot-uniffi",
"paste", "paste",
"static_assertions", "static_assertions",
] ]
[[package]] [[package]]
name = "uniffi_macros" name = "uniffi_macros"
version = "0.25.3" version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11cf7a58f101fcedafa5b77ea037999b88748607f0ef3a33eaa0efc5392e92e4" checksum = "12c65a5b12ec544ef136693af8759fb9d11aefce740fb76916721e876639033b"
dependencies = [ dependencies = [
"bincode", "bincode",
"camino", "camino",
@ -637,15 +646,14 @@ dependencies = [
"serde", "serde",
"syn", "syn",
"toml", "toml",
"uniffi_build",
"uniffi_meta", "uniffi_meta",
] ]
[[package]] [[package]]
name = "uniffi_meta" name = "uniffi_meta"
version = "0.25.3" version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71dc8573a7b1ac4b71643d6da34888273ebfc03440c525121f1b3634ad3417a2" checksum = "4a74ed96c26882dac1ca9b93ca23c827e284bacbd7ec23c6f0b0372f747d59e4"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -655,9 +663,9 @@ dependencies = [
[[package]] [[package]]
name = "uniffi_testing" name = "uniffi_testing"
version = "0.25.3" version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "118448debffcb676ddbe8c5305fb933ab7e0123753e659a71dc4a693f8d9f23c" checksum = "6a6f984f0781f892cc864a62c3a5c60361b1ccbd68e538e6c9fbced5d82268ac"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"camino", "camino",
@ -668,11 +676,12 @@ dependencies = [
[[package]] [[package]]
name = "uniffi_udl" name = "uniffi_udl"
version = "0.25.3" version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "889edb7109c6078abe0e53e9b4070cf74a6b3468d141bdf5ef1bd4d1dc24a1c3" checksum = "037820a4cfc4422db1eaa82f291a3863c92c7d1789dc513489c36223f9b4cdfc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"textwrap",
"uniffi_meta", "uniffi_meta",
"uniffi_testing", "uniffi_testing",
"weedle2", "weedle2",
@ -686,9 +695,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "weedle2" name = "weedle2"
version = "4.0.0" version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e79c5206e1f43a2306fd64bdb95025ee4228960f2e6c5a8b173f3caaf807741" checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e"
dependencies = [ dependencies = [
"nom", "nom",
] ]

View file

@ -1,6 +1,6 @@
[package] [package]
name = "servicepoint_binding_uniffi" name = "servicepoint_binding_uniffi"
version = "0.13.1" version = "0.15.0"
publish = false publish = false
edition = "2021" edition = "2021"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
@ -14,15 +14,18 @@ keywords = ["cccb", "cccb-servicepoint", "uniffi"]
crate-type = ["cdylib"] crate-type = ["cdylib"]
[build-dependencies] [build-dependencies]
uniffi = { version = "0.25.3", features = ["build"] } uniffi = { version = "0.28.3", features = ["build"] }
[dependencies] [dependencies]
uniffi = { version = "0.25.3" } uniffi = { version = "0.28.3" }
thiserror = "2.0" thiserror = "2.0"
paste = "1.0.15"
[dependencies.servicepoint] [dependencies.servicepoint]
version = "0.13.1" version = "0.15.0"
features = ["all_compressions"] features = ["all_compressions"]
git = "https://git.berlin.ccc.de/servicepoint/servicepoint.git"
branch = "next"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View file

@ -2,16 +2,16 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1739357830, "lastModified": 1749494155,
"narHash": "sha256-9xim3nJJUFbVbJCz48UP4fGRStVW5nv4VdbimbKxJ3I=", "narHash": "sha256-FG4DEYBpROupu758beabUk9lhrblSf5hnv84v1TLqMc=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "0ff09db9d034a04acd4e8908820ba0b410d7a33a", "rev": "88331c17ba434359491e8d5889cce872464052c2",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nixos", "owner": "nixos",
"ref": "nixos-24.11", "ref": "nixos-25.05",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }

View file

@ -2,7 +2,7 @@
description = "Flake for the servicepoint library."; description = "Flake for the servicepoint library.";
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
}; };
outputs = outputs =

View file

@ -1,77 +0,0 @@
use servicepoint::{DataRef, Grid};
use std::sync::{Arc, RwLock};
#[derive(uniffi::Object)]
pub struct Bitmap {
pub(crate) actual: RwLock<servicepoint::Bitmap>,
}
impl Bitmap {
fn internal_new(actual: servicepoint::Bitmap) -> Arc<Self> {
Arc::new(Self {
actual: RwLock::new(actual),
})
}
}
#[uniffi::export]
impl Bitmap {
#[uniffi::constructor]
pub fn new(width: u64, height: u64) -> Arc<Self> {
Self::internal_new(servicepoint::Bitmap::new(
width as usize,
height as usize,
))
}
#[uniffi::constructor]
pub fn new_max_sized() -> Arc<Self> {
Self::internal_new(servicepoint::Bitmap::max_sized())
}
#[uniffi::constructor]
pub fn load(width: u64, height: u64, data: Vec<u8>) -> Arc<Self> {
Self::internal_new(servicepoint::Bitmap::load(
width as usize,
height as usize,
&data,
))
}
#[uniffi::constructor]
pub fn clone(other: &Arc<Self>) -> Arc<Self> {
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<u8> {
self.actual.read().unwrap().data_ref().to_vec()
}
}

View file

@ -1,61 +0,0 @@
use std::sync::{Arc, RwLock};
#[derive(uniffi::Object)]
pub struct BitVec {
pub(crate) actual: RwLock<servicepoint::BitVec>,
}
impl BitVec {
fn internal_new(actual: servicepoint::BitVec) -> Arc<Self> {
Arc::new(Self {
actual: RwLock::new(actual),
})
}
}
#[uniffi::export]
impl BitVec {
#[uniffi::constructor]
pub fn new(size: u64) -> Arc<Self> {
Self::internal_new(servicepoint::BitVec::repeat(false, size as usize))
}
#[uniffi::constructor]
pub fn load(data: Vec<u8>) -> Arc<Self> {
Self::internal_new(servicepoint::BitVec::from_slice(&data))
}
#[uniffi::constructor]
pub fn clone(other: &Arc<Self>) -> Arc<Self> {
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<u8> {
self.actual.read().unwrap().clone().into_vec()
}
}

21
src/brightness.rs Normal file
View file

@ -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<Self>
where
Self: Sized,
{
Ok(Brightness::try_from(val)
.map_err(|value| ServicePointError::InvalidBrightness { value })?)
}
fn from_custom(obj: Self) -> Self::Builtin {
obj.into()
}
}

View file

@ -1,86 +0,0 @@
use servicepoint::{Brightness, DataRef, Grid};
use std::sync::{Arc, RwLock};
#[derive(uniffi::Object)]
pub struct BrightnessGrid {
pub(crate) actual: RwLock<servicepoint::BrightnessGrid>,
}
impl BrightnessGrid {
fn internal_new(actual: servicepoint::BrightnessGrid) -> Arc<Self> {
Arc::new(Self {
actual: RwLock::new(actual),
})
}
}
#[uniffi::export]
impl BrightnessGrid {
#[uniffi::constructor]
pub fn new(width: u64, height: u64) -> Arc<Self> {
Self::internal_new(servicepoint::BrightnessGrid::new(
width as usize,
height as usize,
))
}
#[uniffi::constructor]
pub fn load(width: u64, height: u64, data: Vec<u8>) -> Arc<Self> {
Self::internal_new(servicepoint::BrightnessGrid::saturating_load(
width as usize,
height as usize,
&data,
))
}
#[uniffi::constructor]
pub fn clone(other: &Arc<Self>) -> Arc<Self> {
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<u8> {
self.actual
.read()
.unwrap()
.data_ref()
.iter()
.map(u8::from)
.collect()
}
}

View file

@ -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<servicepoint::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]
pub fn new(width: u64, height: u64) -> Arc<Self> {
Self::internal_new(servicepoint::CharGrid::new(
width as usize,
height as usize,
))
}
#[uniffi::constructor]
pub fn load(data: String) -> Arc<Self> {
Self::internal_new(servicepoint::CharGrid::from(&*data))
}
#[uniffi::constructor]
pub fn clone(other: &Arc<Self>) -> Arc<Self> {
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::<Vec<_>>())
.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::<Vec<_>>())
.map_err(CharGridError::from)
}
pub fn get_row(&self, y: u64) -> Result<String, CharGridError> {
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<String, CharGridError> {
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> {
Cp437Grid::internal_new(servicepoint::Cp437Grid::from(
&*self.actual.read().unwrap(),
))
}
}
impl CharGrid {
pub(crate) fn internal_new(actual: servicepoint::CharGrid) -> Arc<Self> {
Arc::new(Self {
actual: RwLock::new(actual),
})
}
fn str_to_char(value: String) -> Result<char, CharGridError> {
if value.len() != 1 {
return Err(CharGridError::StringNotOneChar { value });
}
let value = value.chars().nth(0).unwrap();
Ok(value)
}
}
impl From<SetValueSeriesError> 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,
}
}
}
}
}

View file

@ -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<Command> {
Arc::new(Command { actual })
}
}
#[uniffi::export]
impl Command {
#[uniffi::constructor]
pub fn clear() -> Arc<Self> {
Self::internal_new(servicepoint::Command::Clear)
}
#[uniffi::constructor]
pub fn brightness(brightness: u8) -> Result<Arc<Self>, 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> {
Self::internal_new(servicepoint::Command::FadeOut)
}
#[uniffi::constructor]
pub fn hard_reset() -> Arc<Self> {
Self::internal_new(servicepoint::Command::HardReset)
}
#[uniffi::constructor]
pub fn bitmap_linear_win(
offset_x: u64,
offset_y: u64,
bitmap: &Arc<Bitmap>,
compression: CompressionCode,
) -> Arc<Self> {
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<BrightnessGrid>,
) -> Arc<Self> {
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<BitVec>,
compression: CompressionCode,
) -> Arc<Self> {
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<BitVec>,
compression: CompressionCode,
) -> Arc<Self> {
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<BitVec>,
compression: CompressionCode,
) -> Arc<Self> {
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<BitVec>,
compression: CompressionCode,
) -> Arc<Self> {
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<Cp437Grid>,
) -> Arc<Self> {
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<CharGrid>,
) -> Arc<Self> {
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<Self>) -> Arc<Self> {
Self::internal_new(other.actual.clone())
}
pub fn equals(&self, other: &Command) -> bool {
self.actual == other.actual
}
}

31
src/commands/bitmap.rs Normal file
View file

@ -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<Bitmap>,
compression: CompressionCode,
) -> Arc<Self> {
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)
}
}

52
src/commands/bitvec.rs Normal file
View file

@ -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<BitVec>,
compression: CompressionCode,
operation: BinaryOperation,
) -> Arc<Self> {
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<BinaryOperation> 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,
}
}
}

View file

@ -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<BrightnessGrid>,
) -> Arc<Self> {
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)
}
}

19
src/commands/cc_only.rs Normal file
View file

@ -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> {
Self::internal_new(::servicepoint::$command_struct)
}
}
};
}
command_code_only_command!(ClearCommand);
command_code_only_command!(HardResetCommand);
command_code_only_command!(FadeOutCommand);

24
src/commands/char_grid.rs Normal file
View file

@ -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<CharGrid>,
) -> Arc<Self> {
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)
}
}

24
src/commands/cp437.rs Normal file
View file

@ -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<Cp437Grid>,
) -> Arc<Self> {
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)
}
}

View file

@ -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> {
Self::internal_new(servicepoint::GlobalBrightnessCommand::from(
brightness,
))
}
}

66
src/commands/mod.rs Normal file
View file

@ -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<Arc<crate::packet::Packet>, 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::packet::Packet>,
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<dyn crate::commands::Command> {
::std::sync::Arc::new(self.clone())
}
}
impl crate::commands::Command for $command {
fn as_packet(
&self,
) -> Result<
Arc<crate::packet::Packet>,
crate::errors::ServicePointError,
> {
$command::as_packet(&self)
}
}
};
}
pub(crate) use wrap_command;

View file

@ -12,3 +12,31 @@ pub enum CompressionCode {
/// compress using Zstandard /// compress using Zstandard
Zstd = 0x7a73, Zstd = 0x7a73,
} }
impl From<servicepoint::CompressionCode> 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<CompressionCode> 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,
}
}
}

View file

@ -1,36 +1,39 @@
use std::sync::Arc; use crate::commands::Command;
use crate::{errors::ServicePointError, packet::Packet};
use crate::command::Command; use servicepoint::UdpSocketExt;
use crate::errors::ServicePointError; use std::{net::UdpSocket, sync::Arc};
#[derive(uniffi::Object)] #[derive(uniffi::Object)]
pub struct Connection { pub struct Connection {
actual: servicepoint::Connection, actual: UdpSocket,
} }
#[uniffi::export] #[uniffi::export]
impl Connection { impl Connection {
#[uniffi::constructor] #[uniffi::constructor]
pub fn new(host: String) -> Result<Arc<Self>, ServicePointError> { pub fn new(host: String) -> Result<Arc<Self>, ServicePointError> {
servicepoint::Connection::open(host) UdpSocket::bind_connect(host)
.map(|actual| Arc::new(Connection { actual })) .map(|actual| Arc::new(Connection { actual }))
.map_err(|err| ServicePointError::IoError { .map_err(|err| ServicePointError::IoError {
error: err.to_string(), error: err.to_string(),
}) })
} }
#[uniffi::constructor] pub fn send_packet(
pub fn new_fake() -> Arc<Self> { &self,
Arc::new(Self { command: Arc<Packet>,
actual: servicepoint::Connection::Fake, ) -> 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<Command>) -> Result<(), ServicePointError> { pub fn send_command(
self.actual.send(command.actual.clone()).map_err(|err| { &self,
ServicePointError::IoError { command: Arc<dyn Command>,
error: format!("{err:?}"), ) -> Result<(), ServicePointError> {
} self.send_packet(command.as_packet()?)
})
} }
} }

38
src/containers/bitmap.rs Normal file
View file

@ -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> {
Self::internal_new(
servicepoint::Bitmap::new(width as usize, height as usize).unwrap(),
)
}
#[uniffi::constructor]
pub fn new_max_sized() -> Arc<Self> {
Self::internal_new(servicepoint::Bitmap::max_sized())
}
#[uniffi::constructor]
pub fn load(width: u64, height: u64, data: Vec<u8>) -> Arc<Self> {
// TODO: throw exception
Self::internal_new(
servicepoint::Bitmap::load(width as usize, height as usize, &data)
.unwrap(),
)
}
pub fn copy_raw(&self) -> Vec<u8> {
self.read().deref().into()
}
}

39
src/containers/bitvec.rs Normal file
View file

@ -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> {
Self::internal_new(servicepoint::DisplayBitVec::repeat(
false,
size as usize,
))
}
#[uniffi::constructor]
pub fn load(data: Vec<u8>) -> Arc<Self> {
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<u8> {
self.read().clone().into_vec()
}
}

View file

@ -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> {
Self::internal_new(servicepoint::BrightnessGrid::new(
width as usize,
height as usize,
))
}
#[uniffi::constructor]
pub fn load(width: u64, height: u64, data: Vec<u8>) -> Arc<Self> {
Self::internal_new(
servicepoint::BrightnessGrid::saturating_load(
width as usize,
height as usize,
&data,
)
.unwrap(),
)
}
pub fn copy_raw(&self) -> Vec<u8> {
self.read().deref().into()
}
}

123
src/containers/char_grid.rs Normal file
View file

@ -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> {
Self::internal_new(servicepoint::CharGrid::new(
width as usize,
height as usize,
))
}
#[uniffi::constructor]
pub fn load(data: String) -> Arc<Self> {
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<String, ServicePointError> {
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::<Vec<_>>())
.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::<Vec<_>>())
.map_err(ServicePointError::from)
}
pub fn get_row(&self, y: u64) -> Result<String, ServicePointError> {
self.read()
.get_row(y as usize)
.map(String::from_iter)
.ok_or(ServicePointError::OutOfBounds)
}
pub fn get_col(&self, x: u64) -> Result<String, ServicePointError> {
self.read()
.get_col(x as usize)
.map(String::from_iter)
.ok_or(ServicePointError::OutOfBounds)
}
pub fn to_cp437(&self) -> Arc<Cp437Grid> {
Cp437Grid::internal_new(servicepoint::Cp437Grid::from(&*self.read()))
}
}
impl CharGrid {
fn str_to_char(value: String) -> Result<char, ServicePointError> {
if value.len() != 1 {
return Err(ServicePointError::StringNotOneChar { value });
}
let value = value.chars().nth(0).unwrap();
Ok(value)
}
}
impl From<SetValueSeriesError> 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,
}
}
}
}
}

View file

@ -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> {
Self::internal_new(servicepoint::Cp437Grid::new(
width as usize,
height as usize,
))
}
#[uniffi::constructor]
pub fn load(width: u64, height: u64, data: Vec<u8>) -> Arc<Self> {
Self::internal_new(
servicepoint::Cp437Grid::load(
width as usize,
height as usize,
&data,
)
.unwrap(),
)
}
pub fn copy_raw(&self) -> Vec<u8> {
self.read().deref().into()
}
pub fn to_utf8(&self) -> Arc<CharGrid> {
CharGrid::internal_new(servicepoint::CharGrid::from(&*self.read()))
}
}

46
src/containers/mod.rs Normal file
View file

@ -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;

View file

@ -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<servicepoint::Cp437Grid>,
}
impl Cp437Grid {
pub(crate) fn internal_new(actual: servicepoint::Cp437Grid) -> Arc<Self> {
Arc::new(Self {
actual: RwLock::new(actual),
})
}
}
#[uniffi::export]
impl Cp437Grid {
#[uniffi::constructor]
pub fn new(width: u64, height: u64) -> Arc<Self> {
Self::internal_new(servicepoint::Cp437Grid::new(
width as usize,
height as usize,
))
}
#[uniffi::constructor]
pub fn load(width: u64, height: u64, data: Vec<u8>) -> Arc<Self> {
Self::internal_new(servicepoint::Cp437Grid::load(
width as usize,
height as usize,
&data,
))
}
#[uniffi::constructor]
pub fn clone(other: &Arc<Self>) -> Arc<Self> {
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<u8> {
self.actual.read().unwrap().data_ref().to_vec()
}
pub fn to_utf8(&self) -> Arc<CharGrid> {
CharGrid::internal_new(servicepoint::CharGrid::from(
&*self.actual.read().unwrap(),
))
}
}

View file

@ -4,4 +4,12 @@ pub enum ServicePointError {
IoError { error: String }, IoError { error: String },
#[error("The specified brightness value {value} is out of range")] #[error("The specified brightness value {value} is out of range")]
InvalidBrightness { value: u8 }, 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,
} }

View file

@ -1,12 +1,11 @@
uniffi::setup_scaffolding!(); uniffi::setup_scaffolding!();
mod bitmap; pub mod brightness;
mod bitvec; pub mod commands;
mod brightness_grid; pub mod compression_code;
mod char_grid; pub mod connection;
mod command; pub mod constants;
mod compression_code; pub mod containers;
mod connection; pub mod errors;
mod constants; pub mod macros;
mod cp437_grid; mod packet;
mod errors;

128
src/macros.rs Normal file
View file

@ -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<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(
&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<Self>,
) -> ::std::sync::Arc<Self> {
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<H: ::std::hash::Hasher>(&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, [<get_ $attr_name>]);
}
};
}
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, [<set_ $attr_name>]);
}
};
}
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,
};

13
src/packet.rs Normal file
View file

@ -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<u8> {
Vec::from(&*self.read())
}
}