Skip to content

Commit 42a5aa6

Browse files
committed
ffi: init negentropy-ffi
1 parent 35ca4e6 commit 42a5aa6

File tree

9 files changed

+250
-0
lines changed

9 files changed

+250
-0
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ members = [
33
"negentropy",
44
"negentropy/fuzz/harness",
55
"negentropy/fuzz/perf",
6+
"negentropy-ffi",
67
]
8+
resolver = "2"
79

810
[profile.release]
911
lto = true

negentropy-ffi/Cargo.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "negentropy-ffi"
3+
version = "0.1.0"
4+
edition = "2021"
5+
authors = ["Yuki Kishimoto <[email protected]>"]
6+
publish = false
7+
8+
[lib]
9+
name = "negentropy_ffi"
10+
crate-type = ["lib", "cdylib", "staticlib"]
11+
12+
[[bin]]
13+
name = "uniffi-bindgen"
14+
path = "uniffi-bindgen.rs"
15+
16+
[dependencies]
17+
negentropy = { path = "../negentropy" }
18+
parking_lot = "0.12"
19+
uniffi = { version = "0.24", features = ["cli"] }
20+
21+
[build-dependencies]
22+
uniffi = { version = "0.24", features = ["build"] }
23+

negentropy-ffi/build.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) 2023 Yuki Kishimoto
2+
// Distributed under the MIT software license
3+
4+
fn main() {
5+
uniffi::generate_scaffolding("./src/negentropy.udl").expect("Building the UDL file failed");
6+
}

negentropy-ffi/src/bytes.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) 2023 Yuki Kishimoto
2+
// Distributed under the MIT software license
3+
4+
use core::ops::Deref;
5+
6+
use crate::error::Result;
7+
8+
pub struct Bytes {
9+
inner: negentropy::Bytes,
10+
}
11+
12+
impl Deref for Bytes {
13+
type Target = negentropy::Bytes;
14+
fn deref(&self) -> &Self::Target {
15+
&self.inner
16+
}
17+
}
18+
19+
impl From<negentropy::Bytes> for Bytes {
20+
fn from(inner: negentropy::Bytes) -> Self {
21+
Self { inner }
22+
}
23+
}
24+
25+
impl Bytes {
26+
pub fn new(bytes: Vec<u8>) -> Self {
27+
Self {
28+
inner: negentropy::Bytes::new(bytes)
29+
}
30+
}
31+
32+
pub fn from_hex(data: String) -> Result<Self> {
33+
Ok(Self {
34+
inner: negentropy::Bytes::from_hex(data)?
35+
})
36+
}
37+
38+
pub fn as_hex(&self) -> String {
39+
self.inner.as_hex()
40+
}
41+
42+
pub fn as_bytes(&self) -> Vec<u8> {
43+
self.inner.as_bytes().to_vec()
44+
}
45+
}

negentropy-ffi/src/error.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) 2023 Yuki Kishimoto
2+
// Distributed under the MIT software license
3+
4+
use core::fmt;
5+
6+
pub type Result<T, E = NegentropyError> = std::result::Result<T, E>;
7+
8+
#[derive(Debug)]
9+
pub enum NegentropyError {
10+
Generic { err: String },
11+
}
12+
13+
impl fmt::Display for NegentropyError {
14+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15+
match self {
16+
Self::Generic { err } => write!(f, "{err}"),
17+
}
18+
}
19+
}
20+
21+
impl From<negentropy::Error> for NegentropyError {
22+
fn from(e: negentropy::Error) -> Self {
23+
Self::Generic { err: e.to_string() }
24+
}
25+
}

negentropy-ffi/src/lib.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright (c) 2023 Yuki Kishimoto
2+
// Distributed under the MIT software license
3+
4+
use std::ops::Deref;
5+
use std::sync::Arc;
6+
7+
use parking_lot::RwLock;
8+
9+
mod error;
10+
mod bytes;
11+
12+
use self::error::Result;
13+
pub use self::bytes::Bytes;
14+
pub use self::error::NegentropyError;
15+
16+
pub struct ReconcileWithIds {
17+
pub have_ids: Vec<Arc<Bytes>>,
18+
pub need_ids: Vec<Arc<Bytes>>,
19+
pub output: Option<Arc<Bytes>>,
20+
}
21+
22+
pub struct Negentropy {
23+
inner: RwLock<negentropy::Negentropy>,
24+
}
25+
26+
impl Negentropy {
27+
pub fn new(id_size: u8, frame_size_limit: Option<u64>) -> Result<Self> {
28+
Ok(Self {
29+
inner: RwLock::new(negentropy::Negentropy::new(id_size as usize, frame_size_limit)?)
30+
})
31+
}
32+
33+
pub fn id_size(&self) -> u64 {
34+
self.inner.read().id_size() as u64
35+
}
36+
37+
/// Check if current instance it's an initiator
38+
pub fn is_initiator(&self) -> bool {
39+
self.inner.read().is_initiator()
40+
}
41+
42+
/// Check if sealed
43+
pub fn is_sealed(&self) -> bool {
44+
self.inner.read().is_sealed()
45+
}
46+
47+
/// Check if need to continue
48+
pub fn continuation_needed(&self) -> bool {
49+
self.inner.read().continuation_needed()
50+
}
51+
52+
pub fn add_item(&self, created_at: u64, id: Arc<Bytes>) -> Result<()> {
53+
let mut negentropy = self.inner.write();
54+
Ok(negentropy.add_item(created_at, id.as_ref().deref().clone())?)
55+
}
56+
57+
pub fn seal(&self) -> Result<()> {
58+
let mut negentropy = self.inner.write();
59+
Ok(negentropy.seal()?)
60+
}
61+
62+
/// Initiate reconciliation set
63+
pub fn initiate(&self) -> Result<Arc<Bytes>> {
64+
let mut negentropy = self.inner.write();
65+
Ok(Arc::new(negentropy.initiate()?.into()))
66+
}
67+
68+
pub fn reconcile(&self, query: Arc<Bytes>) -> Result<Arc<Bytes>> {
69+
let mut negentropy = self.inner.write();
70+
Ok(Arc::new(negentropy.reconcile(query.as_ref().deref())?.into()))
71+
}
72+
73+
pub fn reconcile_with_ids(
74+
&self,
75+
query: Arc<Bytes>,
76+
) -> Result<ReconcileWithIds> {
77+
let mut negentropy = self.inner.write();
78+
let mut have_ids: Vec<negentropy::Bytes> = Vec::new();
79+
let mut need_ids: Vec<negentropy::Bytes> = Vec::new();
80+
let output: Option<negentropy::Bytes> = negentropy.reconcile_with_ids(query.as_ref().deref(), &mut have_ids, &mut need_ids)?;
81+
Ok(ReconcileWithIds {
82+
have_ids: have_ids.into_iter().map(|id| Arc::new(id.into())).collect(),
83+
need_ids: need_ids.into_iter().map(|id| Arc::new(id.into())).collect(),
84+
output: output.map(|o| Arc::new(o.into()))
85+
})
86+
}
87+
}
88+
89+
90+
// UDL
91+
uniffi::include_scaffolding!("negentropy");

negentropy-ffi/src/negentropy.udl

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) 2022-2023 Yuki Kishimoto
2+
// Distributed under the MIT software license
3+
4+
namespace negentropy {};
5+
6+
[Error]
7+
interface NegentropyError {
8+
Generic(string err);
9+
};
10+
11+
interface Bytes {
12+
constructor(bytes bytes);
13+
[Throws=NegentropyError, Name=from_hex]
14+
constructor(string data);
15+
string as_hex();
16+
bytes as_bytes();
17+
};
18+
19+
dictionary ReconcileWithIds {
20+
sequence<Bytes> have_ids;
21+
sequence<Bytes> need_ids;
22+
Bytes? output;
23+
};
24+
25+
interface Negentropy {
26+
[Throws=NegentropyError]
27+
constructor(u8 id_size, u64? frame_size_limit);
28+
u64 id_size();
29+
boolean is_initiator();
30+
boolean is_sealed();
31+
boolean continuation_needed();
32+
[Throws=NegentropyError]
33+
void add_item(u64 created_at, Bytes id);
34+
[Throws=NegentropyError]
35+
void seal();
36+
[Throws=NegentropyError]
37+
Bytes initiate();
38+
[Throws=NegentropyError]
39+
Bytes reconcile(Bytes query);
40+
[Throws=NegentropyError]
41+
ReconcileWithIds reconcile_with_ids(Bytes query);
42+
};

negentropy-ffi/uniffi-bindgen.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) 2023 Yuki Kishimoto
2+
// Distributed under the MIT software license
3+
4+
fn main() {
5+
uniffi::uniffi_bindgen_main()
6+
}

negentropy-ffi/uniffi.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[bindings.kotlin]
2+
package_name = "negentropy"
3+
cdylib_name = "negentropy_ffi"
4+
5+
[bindings.swift]
6+
ffi_module_filename = "negentropyFFI"
7+
cdylib_name = "negentropy_ffi"
8+
9+
[bindings.python]
10+
cdylib_name = "negentropy_ffi"

0 commit comments

Comments
 (0)