From a291e1cb540f76334eea13d597a54311b33d21e3 Mon Sep 17 00:00:00 2001 From: Alejandro Cabeza Romero Date: Fri, 24 Apr 2026 12:04:05 +0200 Subject: [PATCH] Implement Rust-side types. --- .../Cargo.lock | 56 ++++++++++++++++++ .../Cargo.toml | 1 + .../src/core/bytes.rs | 13 +++++ .../src/core/mod.rs | 4 ++ .../src/core/status.rs | 43 ++++++++++++++ .../src/core/witness_input.rs | 57 +++++++++++++++++++ .../src/ffi/status.rs | 9 ++- 7 files changed, 181 insertions(+), 2 deletions(-) diff --git a/rust/logos-blockchain-circuits-types/Cargo.lock b/rust/logos-blockchain-circuits-types/Cargo.lock index 9f11a54..464f288 100644 --- a/rust/logos-blockchain-circuits-types/Cargo.lock +++ b/rust/logos-blockchain-circuits-types/Cargo.lock @@ -13,4 +13,60 @@ name = "logos-blockchain-circuits-types" version = "0.1.0" dependencies = [ "libc", + "thiserror", ] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" diff --git a/rust/logos-blockchain-circuits-types/Cargo.toml b/rust/logos-blockchain-circuits-types/Cargo.toml index 081d099..b13af88 100644 --- a/rust/logos-blockchain-circuits-types/Cargo.toml +++ b/rust/logos-blockchain-circuits-types/Cargo.toml @@ -5,3 +5,4 @@ edition = "2024" [dependencies] libc = "0.2.185" +thiserror = "2.0.18" diff --git a/rust/logos-blockchain-circuits-types/src/core/bytes.rs b/rust/logos-blockchain-circuits-types/src/core/bytes.rs index e69de29..5afe60f 100644 --- a/rust/logos-blockchain-circuits-types/src/core/bytes.rs +++ b/rust/logos-blockchain-circuits-types/src/core/bytes.rs @@ -0,0 +1,13 @@ +use crate::ffi; + +pub struct Bytes(Vec); + +impl From for Bytes { + fn from(mut ffi_value: ffi::Bytes) -> Self { + let raw = unsafe { + std::slice::from_raw_parts(ffi_value.data, ffi_value.size).to_vec() + }; + unsafe { ffi::free_bytes(&mut ffi_value); } + Self(raw) + } +} diff --git a/rust/logos-blockchain-circuits-types/src/core/mod.rs b/rust/logos-blockchain-circuits-types/src/core/mod.rs index adabe2d..f035abb 100644 --- a/rust/logos-blockchain-circuits-types/src/core/mod.rs +++ b/rust/logos-blockchain-circuits-types/src/core/mod.rs @@ -1,3 +1,7 @@ pub mod bytes; pub mod status; pub mod witness_input; + +pub use bytes::Bytes; +pub use status::{Result, Error}; +pub use witness_input::WitnessInput; diff --git a/rust/logos-blockchain-circuits-types/src/core/status.rs b/rust/logos-blockchain-circuits-types/src/core/status.rs index e69de29..e92035f 100644 --- a/rust/logos-blockchain-circuits-types/src/core/status.rs +++ b/rust/logos-blockchain-circuits-types/src/core/status.rs @@ -0,0 +1,43 @@ +use std::ffi::CStr; +use thiserror::Error; +use crate::ffi::status::Code as FfiStatusCode; + +pub type DynError = Box; +pub type Result = std::result::Result; + +#[derive(Debug, Error)] +pub enum Error { + #[error("Invalid input")] + InvalidInput, + #[error("Out of memory")] + OutOfMemory, + #[error(transparent)] + Other(#[from] DynError), +} + +impl TryFrom for () { + type Error = Error; + + fn try_from(status: crate::ffi::Status) -> Result<()> { + match status.code { + FfiStatusCode::Ok => Ok(()), + FfiStatusCode::DynError => { + let message: Option<&CStr> = + if status.has_message() { + let status_message = unsafe { + CStr::from_ptr(status.message.as_ptr()) + }; + Some(status_message) + } else { + None + }; + let error_message = message + .map(|inner| DynError::from(inner.to_string_lossy().to_owned())) + .unwrap_or_else(|| DynError::from("Unknown error")); + Err(Error::Other(error_message)) + }, + FfiStatusCode::InvalidInput => Err(Error::InvalidInput), + FfiStatusCode::OutOfMemory => Err(Error::OutOfMemory), + } + } +} diff --git a/rust/logos-blockchain-circuits-types/src/core/witness_input.rs b/rust/logos-blockchain-circuits-types/src/core/witness_input.rs index e69de29..c3d3f9c 100644 --- a/rust/logos-blockchain-circuits-types/src/core/witness_input.rs +++ b/rust/logos-blockchain-circuits-types/src/core/witness_input.rs @@ -0,0 +1,57 @@ +use std::ffi::{c_char, CString}; +use crate::ffi; + +pub struct WitnessInput { + dat: Vec, + inputs_json: String, +} + +impl WitnessInput { + #[must_use] + pub const fn new(dat: Vec, inputs_json: String) -> Self { + Self { dat, inputs_json } + } + + #[must_use] + pub fn as_ffi(&'_ self) -> WitnessInputFfiGuard<'_> { + WitnessInputFfiGuard::new(self) + } +} + +/// Represents a guard for managing the lifetime of a WitnessInput in FFI. +/// This struct ensures that the memory allocated for the FFI representation of WitnessInput is +/// properly released when it goes out of scope. +pub struct WitnessInputFfiGuard<'a> { + ffi: ffi::WitnessInput, + _lifetime: std::marker::PhantomData<&'a WitnessInput>, +} + +impl<'a> WitnessInputFfiGuard<'a> { + #[must_use] + pub fn new(inner: &'a WitnessInput) -> Self { + let dat = ffi::ConstBytes { data: inner.dat.as_ptr(), size: inner.dat.len() }; + let inputs_json = CString::new(inner.inputs_json.clone()).expect("CString::new failed").into_raw(); + let ffi = ffi::WitnessInput { dat, inputs_json }; + Self { + ffi, + _lifetime: std::marker::PhantomData, + } + } +} + +impl<'a> AsRef for WitnessInputFfiGuard<'a> { + fn as_ref(&self) -> &ffi::WitnessInput { + &self.ffi + } +} + +impl<'a> Drop for WitnessInputFfiGuard<'a> { + fn drop(&mut self) { + if !self.ffi.inputs_json.is_null() { + drop(unsafe { + CString::from_raw(self.ffi.inputs_json as *mut c_char) + }) + } + } +} + diff --git a/rust/logos-blockchain-circuits-types/src/ffi/status.rs b/rust/logos-blockchain-circuits-types/src/ffi/status.rs index 6cb4b68..d4f2395 100644 --- a/rust/logos-blockchain-circuits-types/src/ffi/status.rs +++ b/rust/logos-blockchain-circuits-types/src/ffi/status.rs @@ -1,4 +1,5 @@ use std::cmp::PartialEq; +use std::ffi::c_char; #[repr(C)] #[derive(Debug, PartialEq)] @@ -23,14 +24,14 @@ impl Code { #[derive(Debug)] pub struct Status { pub code: Code, - pub message: String, + pub message: [c_char; 256], } impl Status { pub fn ok() -> Self { Status { code: Code::Ok, - message: String::new(), + message: [0; 256], } } @@ -41,4 +42,8 @@ impl Status { pub fn is_error(&self) -> bool { self.code.is_error() } + + pub fn has_message(&self) -> bool { + self.message[0] != 0 + } }