diff options
| author | Weicao-CatilGrass <1992414357@qq.com> | 2026-03-09 19:42:12 +0800 |
|---|---|---|
| committer | Weicao-CatilGrass <1992414357@qq.com> | 2026-03-09 19:42:12 +0800 |
| commit | f7e36925c566cd8336e71eb507c8a766240f03a0 (patch) | |
| tree | ba92f1d6a69a738e00a1d77b5f19cbbe7c57deab /src | |
| parent | 2827668ab5f38c05f95a0060988313c449436267 (diff) | |
Add C FFI bindings for library usage
Diffstat (limited to 'src')
| -rw-r--r-- | src/chunker/context.rs | 13 | ||||
| -rw-r--r-- | src/chunker/context/ffi.rs | 795 | ||||
| -rw-r--r-- | src/lib.rs | 6 |
3 files changed, 808 insertions, 6 deletions
diff --git a/src/chunker/context.rs b/src/chunker/context.rs index 45283bc..e351b18 100644 --- a/src/chunker/context.rs +++ b/src/chunker/context.rs @@ -1,15 +1,16 @@ -use std::{collections::HashMap, env::current_dir, path::PathBuf, process::exit, str::FromStr}; - -use log::{error, warn}; - use crate::{ chunker::{constants::BUTCK_METADATA_DIR_NAME, rw::storage::hash::ChunkWriteHash}, special_argument, special_flag, storage::{ButckRWError, build, write}, utils::file_input_solve::parse_path_input, }; +use log::{error, warn}; +use std::{collections::HashMap, env::current_dir, path::PathBuf, process::exit, str::FromStr}; + +pub mod ffi; pub struct Butck; + impl Butck { pub fn write(files: Vec<PathBuf>, storage: PathBuf) -> ButckContext { ButckContext::default() @@ -227,8 +228,8 @@ impl ButckContext { } } - fn apply_memmap_read(&mut self, args: &mut Vec<String>) -> bool { - special_flag!(args, "-m", "--memmap-read") + fn apply_memmap_read(&mut self, args: &mut Vec<String>) { + self.memmap_read = special_flag!(args, "-m", "--memmap-read"); } fn apply_register_name(&mut self, args: &mut Vec<String>) { diff --git a/src/chunker/context/ffi.rs b/src/chunker/context/ffi.rs new file mode 100644 index 0000000..c169c18 --- /dev/null +++ b/src/chunker/context/ffi.rs @@ -0,0 +1,795 @@ +#![allow(unused_unsafe)] +use std::{collections::HashMap, env::current_dir, path::PathBuf}; + +use crate::chunker::{ + context::{ButckContext, ButckMethod}, + rw::storage::hash::ChunkWriteHash, +}; + +/// Helper macro to convert C string pointer to Option<String> +/// Returns None if pointer is null or conversion fails +macro_rules! cstr_to_opt_string { + ($ptr:expr) => { + if $ptr.is_null() { + None + } else { + unsafe { + std::ffi::CStr::from_ptr($ptr) + .to_str() + .ok() + .map(|s| s.to_string()) + } + } + }; +} + +/// Helper macro to convert C string pointer to PathBuf +/// Returns empty PathBuf if pointer is null or conversion fails +macro_rules! cstr_to_path { + ($ptr:expr) => { + if $ptr.is_null() { + PathBuf::new() + } else { + unsafe { + std::ffi::CStr::from_ptr($ptr) + .to_str() + .map(PathBuf::from) + .unwrap_or_default() + } + } + }; +} + +/// Helper macro to convert C string pointer to PathBuf with fallback to current directory +/// Returns current directory if pointer is null or conversion fails +macro_rules! cstr_to_path_or_current_dir { + ($ptr:expr) => { + if $ptr.is_null() { + current_dir().unwrap() + } else { + unsafe { + std::ffi::CStr::from_ptr($ptr) + .to_str() + .map(PathBuf::from) + .unwrap_or_else(|_| current_dir().unwrap()) + } + } + }; +} + +#[repr(C)] +pub struct FFIButckContext { + method: u8, + file_paths: *mut *mut std::os::raw::c_char, + file_paths_len: usize, + storage_path: *mut std::os::raw::c_char, + display_boundaries: bool, + stream_read: u32, + stream_read_set: bool, + memmap_read: bool, + register_name: *mut std::os::raw::c_char, + policy_name: *mut std::os::raw::c_char, + chunk_hash: u8, + output_dir: *mut std::os::raw::c_char, + output_file: *mut std::os::raw::c_char, + params_keys: *mut *mut std::os::raw::c_char, + params_values: *mut *mut std::os::raw::c_char, + params_len: usize, +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_Write( + files: *mut *mut std::os::raw::c_char, + files_len: usize, + storage: *mut std::os::raw::c_char, +) -> *mut FFIButckContext { + let mut file_paths = Vec::new(); + if !files.is_null() && files_len > 0 { + for i in 0..files_len { + unsafe { + let ptr = *files.add(i); + if !ptr.is_null() { + let c_str = std::ffi::CStr::from_ptr(ptr); + if let Ok(path_str) = c_str.to_str() { + file_paths.push(PathBuf::from(path_str)); + } + } + } + } + } + + let storage_path = if !storage.is_null() { + unsafe { + let c_str = std::ffi::CStr::from_ptr(storage); + if let Ok(path_str) = c_str.to_str() { + PathBuf::from(path_str) + } else { + PathBuf::new() + } + } + } else { + PathBuf::new() + }; + + let ctx = ButckContext::default() + .with_file_paths(file_paths) + .with_storage_path(storage_path) + .with_write_mode(); + + Box::into_raw(Box::new(FFIButckContext::from(ctx))) +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_Build( + index_files: *mut *mut std::os::raw::c_char, + index_files_len: usize, + storage: *mut std::os::raw::c_char, +) -> *mut FFIButckContext { + let mut file_paths = Vec::new(); + if !index_files.is_null() && index_files_len > 0 { + for i in 0..index_files_len { + unsafe { + let ptr = *index_files.add(i); + if !ptr.is_null() { + let c_str = std::ffi::CStr::from_ptr(ptr); + if let Ok(path_str) = c_str.to_str() { + file_paths.push(PathBuf::from(path_str)); + } + } + } + } + } + + let storage_path = if !storage.is_null() { + unsafe { + let c_str = std::ffi::CStr::from_ptr(storage); + if let Ok(path_str) = c_str.to_str() { + PathBuf::from(path_str) + } else { + PathBuf::new() + } + } + } else { + PathBuf::new() + }; + + let ctx = ButckContext::default() + .with_file_paths(file_paths) + .with_storage_path(storage_path) + .with_build_mode(); + + Box::into_raw(Box::new(FFIButckContext::from(ctx))) +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_Exec(ctx: *mut FFIButckContext) -> bool { + if ctx.is_null() { + return false; + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let butck_ctx = ButckContext::from(*ffi_ctx); + // ffi_ctx is consumed by the dereference above, Box will be dropped automatically + + let runtime = tokio::runtime::Runtime::new().unwrap(); + match runtime.block_on(butck_ctx.exec()) { + Ok(_) => true, + Err(_) => false, + } + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_WithStoragePath( + ctx: *mut FFIButckContext, + storage: *mut std::os::raw::c_char, +) -> *mut FFIButckContext { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let mut butck_ctx = ButckContext::from(*ffi_ctx); + + let storage_path = cstr_to_path!(storage); + + butck_ctx = butck_ctx.with_storage_path(storage_path); + Box::into_raw(Box::new(FFIButckContext::from(butck_ctx))) + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_WithDisplayBoundaries( + ctx: *mut FFIButckContext, + display: bool, +) -> *mut FFIButckContext { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let mut butck_ctx = ButckContext::from(*ffi_ctx); + + butck_ctx = butck_ctx.with_display_boundaries(display); + Box::into_raw(Box::new(FFIButckContext::from(butck_ctx))) + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_WithStreamRead( + ctx: *mut FFIButckContext, + size: u32, + set: bool, +) -> *mut FFIButckContext { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let mut butck_ctx = ButckContext::from(*ffi_ctx); + + let stream_read = if set { Some(size) } else { None }; + butck_ctx = butck_ctx.with_stream_read(stream_read); + Box::into_raw(Box::new(FFIButckContext::from(butck_ctx))) + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_WithMemmapRead( + ctx: *mut FFIButckContext, + use_memmap: bool, +) -> *mut FFIButckContext { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let mut butck_ctx = ButckContext::from(*ffi_ctx); + + butck_ctx = butck_ctx.with_memmap_read(use_memmap); + Box::into_raw(Box::new(FFIButckContext::from(butck_ctx))) + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_WithRegisterName( + ctx: *mut FFIButckContext, + name: *mut std::os::raw::c_char, +) -> *mut FFIButckContext { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let mut butck_ctx = ButckContext::from(*ffi_ctx); + + let register_name = cstr_to_opt_string!(name); + + butck_ctx = butck_ctx.with_register_name(register_name); + Box::into_raw(Box::new(FFIButckContext::from(butck_ctx))) + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_WithPolicyName( + ctx: *mut FFIButckContext, + name: *mut std::os::raw::c_char, +) -> *mut FFIButckContext { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let mut butck_ctx = ButckContext::from(*ffi_ctx); + + let policy_name = cstr_to_opt_string!(name); + + butck_ctx = butck_ctx.with_policy_name(policy_name); + Box::into_raw(Box::new(FFIButckContext::from(butck_ctx))) + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_WithChunkHash(ctx: *mut FFIButckContext, hash: u8) -> *mut FFIButckContext { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let mut butck_ctx = ButckContext::from(*ffi_ctx); + + let chunk_hash = match hash { + 0 => ChunkWriteHash::Blake3, + 1 => ChunkWriteHash::Sha256, + _ => ChunkWriteHash::default(), + }; + + butck_ctx = butck_ctx.with_chunk_hash(chunk_hash); + Box::into_raw(Box::new(FFIButckContext::from(butck_ctx))) + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_WithOutputDir( + ctx: *mut FFIButckContext, + dir: *mut std::os::raw::c_char, +) -> *mut FFIButckContext { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let mut butck_ctx = ButckContext::from(*ffi_ctx); + + let output_dir = cstr_to_path_or_current_dir!(dir); + + butck_ctx = butck_ctx.with_output_dir(output_dir); + Box::into_raw(Box::new(FFIButckContext::from(butck_ctx))) + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_WithOutputFile( + ctx: *mut FFIButckContext, + file: *mut std::os::raw::c_char, +) -> *mut FFIButckContext { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let mut butck_ctx = ButckContext::from(*ffi_ctx); + + let output_file = cstr_to_opt_string!(file).map(PathBuf::from); + + butck_ctx = butck_ctx.with_output_file(output_file); + Box::into_raw(Box::new(FFIButckContext::from(butck_ctx))) + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_WithFilePaths( + ctx: *mut FFIButckContext, + files: *mut *mut std::os::raw::c_char, + files_len: usize, +) -> *mut FFIButckContext { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let mut butck_ctx = ButckContext::from(*ffi_ctx); + + let mut file_paths = Vec::new(); + if !files.is_null() && files_len > 0 { + for i in 0..files_len { + let ptr = *files.add(i); + if !ptr.is_null() { + let c_str = std::ffi::CStr::from_ptr(ptr); + if let Ok(path_str) = c_str.to_str() { + file_paths.push(PathBuf::from(path_str)); + } + } + } + } + + butck_ctx = butck_ctx.with_file_paths(file_paths); + Box::into_raw(Box::new(FFIButckContext::from(butck_ctx))) + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_AddFile( + ctx: *mut FFIButckContext, + file: *mut std::os::raw::c_char, +) -> *mut FFIButckContext { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let mut butck_ctx = ButckContext::from(*ffi_ctx); + + if !file.is_null() { + let c_str = std::ffi::CStr::from_ptr(file); + if let Ok(path_str) = c_str.to_str() { + butck_ctx = butck_ctx.add_file(PathBuf::from(path_str)); + } + } + + Box::into_raw(Box::new(FFIButckContext::from(butck_ctx))) + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_Param( + ctx: *mut FFIButckContext, + key: *mut std::os::raw::c_char, + value: *mut std::os::raw::c_char, +) -> *mut FFIButckContext { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + let ffi_ctx = Box::from_raw(ctx); + let mut butck_ctx = ButckContext::from(*ffi_ctx); + + if !key.is_null() && !value.is_null() { + let key_cstr = std::ffi::CStr::from_ptr(key); + let value_cstr = std::ffi::CStr::from_ptr(value); + + if let (Ok(key_str), Ok(value_str)) = (key_cstr.to_str(), value_cstr.to_str()) { + butck_ctx = butck_ctx.param(key_str.to_string(), value_str.to_string()); + } + } + + Box::into_raw(Box::new(FFIButckContext::from(butck_ctx))) + } +} + +#[unsafe(no_mangle)] +#[allow(nonstandard_style)] +pub extern "C" fn Butck_FreeButckContext(ctx: *mut FFIButckContext) { + if ctx.is_null() { + return; + } + + unsafe { + let ffi_ctx = &mut *ctx; + + // Free file_paths + if !ffi_ctx.file_paths.is_null() && ffi_ctx.file_paths_len > 0 { + for i in 0..ffi_ctx.file_paths_len { + let ptr = *ffi_ctx.file_paths.add(i); + if !ptr.is_null() { + let _ = std::ffi::CString::from_raw(ptr); + } + } + let _ = Box::from_raw(std::slice::from_raw_parts_mut( + ffi_ctx.file_paths, + ffi_ctx.file_paths_len, + )); + } + + // Free storage_path + if !ffi_ctx.storage_path.is_null() { + let _ = std::ffi::CString::from_raw(ffi_ctx.storage_path); + } + + // Free register_name + if !ffi_ctx.register_name.is_null() { + let _ = std::ffi::CString::from_raw(ffi_ctx.register_name); + } + + // Free policy_name + if !ffi_ctx.policy_name.is_null() { + let _ = std::ffi::CString::from_raw(ffi_ctx.policy_name); + } + + // Free output_dir + if !ffi_ctx.output_dir.is_null() { + let _ = std::ffi::CString::from_raw(ffi_ctx.output_dir); + } + + // Free output_file + if !ffi_ctx.output_file.is_null() { + let _ = std::ffi::CString::from_raw(ffi_ctx.output_file); + } + + // Free params + if !ffi_ctx.params_keys.is_null() + && !ffi_ctx.params_values.is_null() + && ffi_ctx.params_len > 0 + { + for i in 0..ffi_ctx.params_len { + let key_ptr = *ffi_ctx.params_keys.add(i); + let value_ptr = *ffi_ctx.params_values.add(i); + + if !key_ptr.is_null() { + let _ = std::ffi::CString::from_raw(key_ptr); + } + if !value_ptr.is_null() { + let _ = std::ffi::CString::from_raw(value_ptr); + } + } + + let _ = Box::from_raw(std::slice::from_raw_parts_mut( + ffi_ctx.params_keys, + ffi_ctx.params_len, + )); + let _ = Box::from_raw(std::slice::from_raw_parts_mut( + ffi_ctx.params_values, + ffi_ctx.params_len, + )); + } + + // Free the context itself + let _ = Box::from_raw(ctx); + } +} + +impl From<ButckContext> for FFIButckContext { + fn from(ctx: ButckContext) -> Self { + // Convert method enum + let method = match ctx.method { + ButckMethod::None => 0, + ButckMethod::Write => 1, + ButckMethod::Build => 2, + }; + + // Convert file paths + let mut file_paths_vec: Vec<*mut std::os::raw::c_char> = Vec::new(); + for path in &ctx.file_paths { + if let Some(c_str) = path.to_str() { + let c_string = std::ffi::CString::new(c_str).unwrap(); + file_paths_vec.push(c_string.into_raw()); + } else { + file_paths_vec.push(std::ptr::null_mut()); + } + } + let file_paths_len = file_paths_vec.len(); + let file_paths = if file_paths_len > 0 { + let mut boxed_slice = file_paths_vec.into_boxed_slice(); + let ptr = boxed_slice.as_mut_ptr(); + std::mem::forget(boxed_slice); + ptr + } else { + std::ptr::null_mut() + }; + + // Convert storage path + let storage_path = if let Some(ref path) = ctx.storage_path { + if let Some(c_str) = path.to_str() { + let c_string = std::ffi::CString::new(c_str).unwrap(); + c_string.into_raw() + } else { + std::ptr::null_mut() + } + } else { + std::ptr::null_mut() + }; + + // Convert stream read + let (stream_read, stream_read_set) = match ctx.stream_read { + Some(size) => (size, true), + None => (0, false), + }; + + // Convert register name + let register_name = if let Some(ref name) = ctx.register_name { + let c_string = std::ffi::CString::new(name.as_str()).unwrap(); + c_string.into_raw() + } else { + std::ptr::null_mut() + }; + + // Convert policy name + let policy_name = if let Some(ref name) = ctx.policy_name { + let c_string = std::ffi::CString::new(name.as_str()).unwrap(); + c_string.into_raw() + } else { + std::ptr::null_mut() + }; + + // Convert chunk hash + let chunk_hash = match ctx.chunk_hash { + ChunkWriteHash::Blake3 => 0, + ChunkWriteHash::Sha256 => 1, + }; + + // Convert output dir + let output_dir = if let Some(c_str) = ctx.output_dir.to_str() { + let c_string = std::ffi::CString::new(c_str).unwrap(); + c_string.into_raw() + } else { + std::ptr::null_mut() + }; + + // Convert output file + let output_file = if let Some(ref path) = ctx.output_file { + if let Some(c_str) = path.to_str() { + let c_string = std::ffi::CString::new(c_str).unwrap(); + c_string.into_raw() + } else { + std::ptr::null_mut() + } + } else { + std::ptr::null_mut() + }; + + // Convert params + let mut params_keys_vec: Vec<*mut std::os::raw::c_char> = Vec::new(); + let mut params_values_vec: Vec<*mut std::os::raw::c_char> = Vec::new(); + + for (key, value) in &ctx.params { + let key_cstring = std::ffi::CString::new(key.as_str()).unwrap(); + let value_cstring = std::ffi::CString::new(value.as_str()).unwrap(); + params_keys_vec.push(key_cstring.into_raw()); + params_values_vec.push(value_cstring.into_raw()); + } + + let params_len = params_keys_vec.len(); + let params_keys = if params_len > 0 { + let mut boxed_slice = params_keys_vec.into_boxed_slice(); + let ptr = boxed_slice.as_mut_ptr(); + std::mem::forget(boxed_slice); + ptr + } else { + std::ptr::null_mut() + }; + + let params_values = if params_len > 0 { + let mut boxed_slice = params_values_vec.into_boxed_slice(); + let ptr = boxed_slice.as_mut_ptr(); + std::mem::forget(boxed_slice); + ptr + } else { + std::ptr::null_mut() + }; + + FFIButckContext { + method, + file_paths, + file_paths_len, + storage_path, + display_boundaries: ctx.display_boundaries, + stream_read, + stream_read_set, + memmap_read: ctx.memmap_read, + register_name, + policy_name, + chunk_hash, + output_dir, + output_file, + params_keys, + params_values, + params_len, + } + } +} + +impl From<FFIButckContext> for ButckContext { + fn from(ffi_ctx: FFIButckContext) -> Self { + // Convert method enum + let method = match ffi_ctx.method { + 0 => ButckMethod::None, + 1 => ButckMethod::Write, + 2 => ButckMethod::Build, + _ => ButckMethod::None, + }; + + // Convert file paths + let mut file_paths = Vec::new(); + if !ffi_ctx.file_paths.is_null() && ffi_ctx.file_paths_len > 0 { + for i in 0..ffi_ctx.file_paths_len { + unsafe { + let ptr = *ffi_ctx.file_paths.add(i); + if !ptr.is_null() { + let c_str = std::ffi::CStr::from_ptr(ptr); + if let Ok(path_str) = c_str.to_str() { + file_paths.push(PathBuf::from(path_str)); + } + } + } + } + } + + // Convert storage path + let storage_path = if !ffi_ctx.storage_path.is_null() { + unsafe { cstr_to_opt_string!(ffi_ctx.storage_path).map(PathBuf::from) } + } else { + None + }; + + // Convert stream read + let stream_read = if ffi_ctx.stream_read_set { + Some(ffi_ctx.stream_read) + } else { + None + }; + + // Convert register name + let register_name = if !ffi_ctx.register_name.is_null() { + unsafe { cstr_to_opt_string!(ffi_ctx.register_name) } + } else { + None + }; + + // Convert policy name + let policy_name = if !ffi_ctx.policy_name.is_null() { + unsafe { cstr_to_opt_string!(ffi_ctx.policy_name) } + } else { + None + }; + + // Convert chunk hash + let chunk_hash = match ffi_ctx.chunk_hash { + 0 => ChunkWriteHash::Blake3, + 1 => ChunkWriteHash::Sha256, + _ => ChunkWriteHash::default(), + }; + + // Convert output dir + let output_dir = if !ffi_ctx.output_dir.is_null() { + unsafe { cstr_to_path_or_current_dir!(ffi_ctx.output_dir) } + } else { + current_dir().unwrap() + }; + + // Convert output file + let output_file = if !ffi_ctx.output_file.is_null() { + unsafe { cstr_to_opt_string!(ffi_ctx.output_file).map(PathBuf::from) } + } else { + None + }; + + // Convert params + let mut params = HashMap::new(); + if !ffi_ctx.params_keys.is_null() + && !ffi_ctx.params_values.is_null() + && ffi_ctx.params_len > 0 + { + for i in 0..ffi_ctx.params_len { + unsafe { + let key_ptr = *ffi_ctx.params_keys.add(i); + let value_ptr = *ffi_ctx.params_values.add(i); + + if !key_ptr.is_null() && !value_ptr.is_null() { + let key_cstr = std::ffi::CStr::from_ptr(key_ptr); + let value_cstr = std::ffi::CStr::from_ptr(value_ptr); + + if let (Ok(key_str), Ok(value_str)) = + (key_cstr.to_str(), value_cstr.to_str()) + { + params.insert(key_str.to_string(), value_str.to_string()); + } + } + } + } + } + + ButckContext { + method, + file_paths, + storage_path, + display_boundaries: ffi_ctx.display_boundaries, + stream_read, + memmap_read: ffi_ctx.memmap_read, + register_name, + policy_name, + chunk_hash, + output_dir, + output_file, + params, + ..Default::default() + } + } +} @@ -6,3 +6,9 @@ pub mod storage { pub use crate::chunker::rw::storage::build::*; pub use crate::chunker::rw::storage::write::*; } + +pub mod ctx { + #[cfg(feature = "ffi")] + pub use crate::chunker::context::ffi::*; + pub use crate::chunker::context::*; +} |
