Enable static linking, libczi is now a submodule.

This commit is contained in:
Wim Pomp
2025-08-12 18:52:46 +02:00
parent 37ede463e0
commit 999af74dd6
13 changed files with 368 additions and 148 deletions

54
.github/workflows/publish.yml vendored Normal file
View File

@@ -0,0 +1,54 @@
name: Publish
on: [push, pull_request, workflow_call]
permissions:
contents: read
jobs:
crates_io_publish:
name: Publish (crates.io)
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: cargo-release Cache
id: cargo_release_cache
uses: actions/cache@v3
with:
path: ~/.cargo/bin/cargo-release
key: ${{ runner.os }}-cargo-release
- run: cargo install cargo-release
if: steps.cargo_release_cache.outputs.cache-hit != 'true'
- name: cargo login
run: cargo login ${{ secrets.CRATES_IO_API_TOKEN }}
# allow-branch HEAD is because GitHub actions switches
# to the tag while building, which is a detached head
# Publishing is currently messy, because:
#
# * `peace_rt_model_core` exports `NativeError` or `WebError` depending on the target.
# * `peace_rt_model_web` fails to build when publishing the workspace for a native target.
# * `peace_rt_model_web` still needs its dependencies to be published before it can be
# published.
# * `peace_rt_model_hack` needs `peace_rt_model_web` to be published before it can be
# published.
#
# We *could* pass through `--no-verify` so `cargo` doesn't build the crate before publishing,
# which is reasonable, since this job only runs after the Linux, Windows, and WASM builds
# have passed.
- name: "cargo release publish"
run: |-
cargo release \
publish \
--workspace \
--all-features \
--allow-branch "main" \
--no-confirm \
--no-verify \
--execute

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "libczi"]
path = libczi
url = https://github.com/ZEISS/libczi.git

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "libczirw-sys" name = "libczirw-sys"
version = "0.1.2" version = "0.2.0"
edition = "2024" edition = "2024"
rust-version = "1.85.1" rust-version = "1.85.1"
authors = ["Wim Pomp <w.pomp@nki.nl>"] authors = ["Wim Pomp <w.pomp@nki.nl>"]
@@ -15,8 +15,13 @@ links = "libCZIAPI"
[dependencies] [dependencies]
anyhow = "1.0.98" anyhow = "1.0.98"
link-cplusplus = "1.0"
[build-dependencies] [build-dependencies]
anyhow = "1.0.98" anyhow = "1.0.98"
bindgen = "0.72.0"
cmake = "0.1.54" cmake = "0.1.54"
git2 = "0.20.2" regex = "1.11.1"
[features]
dynamic = []

View File

@@ -4,4 +4,6 @@ Crate linking to [libCZIAPI](https://github.com/ZEISS/libczi).
This crate attempts to provide save wrappers to objects and functions in libCZIAPI. This crate attempts to provide save wrappers to objects and functions in libCZIAPI.
Direct often unsafe access using pointer is available through the sys module. Direct often unsafe access using pointer is available through the sys module.
This code is licensed with an MIT license, but Zeiss' libCZI has a LGPL license. By default, libCZIAPI will be statically linked. The feature 'dynamic' will switch it to dynamic linking.
This code is licensed with an MIT license, but Zeiss' libCZI which is included as a submodule has a LGPL license.

199
build.rs
View File

@@ -1,90 +1,171 @@
use anyhow::Result; extern crate bindgen;
use anyhow::{Error, Result};
use std::env; use std::env;
use std::fs::OpenOptions;
use std::io::{Read, Seek, Write};
use std::path::PathBuf; use std::path::PathBuf;
#[cfg(not(feature = "dynamic"))]
use std::fmt::Debug;
#[cfg(not(feature = "dynamic"))]
use bindgen::callbacks::ItemInfo;
#[cfg(not(feature = "dynamic"))]
use std::collections::HashMap;
#[cfg(not(feature = "dynamic"))]
use regex::Regex;
fn main() -> Result<()> { fn main() -> Result<()> {
if env::var("DOCS_RS").is_err() { if env::var("DOCS_RS").is_err() {
let out_dir = PathBuf::from(env::var("OUT_DIR")?).canonicalize()?; let out_dir = PathBuf::from(env::var("OUT_DIR")?).canonicalize()?;
let libczi_dir = out_dir.join("libczirw"); let libczi_dir = PathBuf::from("libczi");
let rep = if !libczi_dir.exists() { let libczi_src = libczi_dir.join("Src/libCZI");
git2::Repository::clone("https://github.com/ZEISS/libczi.git", &libczi_dir) let libcziapi_inc = libczi_dir.join("Src/libCZIAPI/inc");
.expect("unable to clone libczirw") let libcziapi_src = libczi_dir.join("Src/libCZIAPI/src");
} else { let libcziapi_h = libcziapi_inc.join("libCZIApi.h");
git2::Repository::open(&libczi_dir)?
};
let (object, _) = rep.revparse_ext("494ac62f853de6ab86458f167fd85a03ee6d4f7e")?;
rep.checkout_tree(&object, None)?;
let dst = cmake::Config::new(&libczi_dir) let dst = cmake::Config::new(&libczi_dir)
.cxxflag("-fms-extensions")
.define("LIBCZI_BUILD_UNITTESTS", "OFF") .define("LIBCZI_BUILD_UNITTESTS", "OFF")
.define("LIBCZI_BUILD_CZICMD", "OFF") .define("LIBCZI_BUILD_CZICMD", "OFF")
.define("LIBCZI_BUILD_DYNLIB", "OFF") .define("LIBCZI_BUILD_DYNLIB", "OFF")
.define("LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_EIGEN3", "OFF") .define("LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_EIGEN3", "OFF")
.define("LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_ZSTD", "OFF") .define("LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_ZSTD", "OFF")
.define("LIBCZI_BUILD_CURL_BASED_STREAM", "OFF") .define("LIBCZI_BUILD_CURL_BASED_STREAM", "OFF")
.define("LIBCZI_BUILD_PREFER_EXTERNAL_PACKAGE_LIBCURL", "OFF") .define("LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_LIBCURL", "OFF")
.define("LIBCZI_BUILD_AZURESDK_BASED_STREAM", "OFF") .define("LIBCZI_BUILD_AZURESDK_BASED_STREAM", "OFF")
.define("LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_RAPIDJSON", "OFF") .define("LIBCZI_BUILD_PREFER_EXTERNALPACKAGE_RAPIDJSON", "OFF")
.define("LIBCZI_BUILD_LIBCZIAPI", "ON") .define("LIBCZI_BUILD_LIBCZIAPI", "ON")
.build(); .build();
// let libcziapi_inc = libczi_dir.join("Src/libCZIAPI/inc"); #[cfg(not(feature = "dynamic"))]
// let libczi_src = libczi_dir.join("Src/libCZI"); let bindings = {
// let libcziapi_src = libczi_dir.join("Src/libCZIAPI/src"); let mut libcziapi_a = out_dir.join("build/Src/libCZIAPI/liblibCZIAPIStatic.a");
// let libczi_h = libcziapi_inc.join("libCZIApi.h"); if !libcziapi_a.exists() {
libcziapi_a = out_dir.join("build/Src/libCZIAPI/liblibCZIAPIStatic.lib");
let import_export = libczi_dir.join("Src/libCZIAPI/inc/importexport.h"); }
{ bindgen::Builder::default().parse_callbacks(Box::new(DeMangler::new(libcziapi_a)?))
let mut file = OpenOptions::new()
.read(true)
.write(true)
.open(&import_export)
.expect("Could not open file");
let mut data = String::new();
file.read_to_string(&mut data).expect("Could not read file");
let data = data.replace(" __declspec(dllexport)", "");
let bytes = data.as_bytes();
(&file).rewind().expect("Could not rewind");
(&file).write_all(bytes).expect("Could not write file");
file.set_len(bytes.len() as u64)
.expect("Could not truncate");
}; };
// let bindings = bindgen::Builder::default() #[cfg(feature = "dynamic")]
// .clang_args([ let bindings = bindgen::Builder::default();
// "-x",
// "c++",
// "-std=c++14",
// "-I",
// libcziapi_inc
// .to_str()
// .ok_or(Error::msg("cannot into string"))?,
// "-I",
// libcziapi_src
// .to_str()
// .ok_or(Error::msg("cannot into string"))?,
// "-I",
// libczi_src
// .to_str()
// .ok_or(Error::msg("cannot into string"))?,
// ])
// .header(libczi_h.to_str().ok_or(Error::msg("cannot into string"))?)
// .generate()
// .expect("Unable to generate bindings");
//
// bindings
// .write_to_file(out_dir.join("lib_czi_api.rs"))
// .expect("Couldn't write bindings!");
let bindings = bindings
.merge_extern_blocks(true)
.clang_args([
"-fms-extensions",
"-x",
"c++",
"-std=c++14",
"-I",
libcziapi_inc
.to_str()
.ok_or(Error::msg("cannot into string"))?,
"-I",
libcziapi_src
.to_str()
.ok_or(Error::msg("cannot into string"))?,
"-I",
libczi_src
.to_str()
.ok_or(Error::msg("cannot into string"))?,
])
.header(
libcziapi_h
.to_str()
.ok_or(Error::msg("cannot into string"))?,
)
.generate()?;
bindings.write_to_file(out_dir.join("lib_czi_api.rs"))?;
#[cfg(not(feature = "dynamic"))]
{
println!(
"cargo:rustc-link-search=native={}",
dst.join("build/Src/libCZIAPI").display()
);
println!("cargo:rustc-link-lib=static=libCZIAPIStatic");
println!(
"cargo:rustc-link-search=native={}",
dst.join("build/Src/libCZI").display()
);
let profile = env::var("PROFILE")?;
match profile.as_str() {
"debug" => println!("cargo:rustc-link-lib=static=libCZIStaticd"),
"release" => println!("cargo:rustc-link-lib=static=libCZIStatic"),
_ => return Err(Error::msg(format!("unsupported profile: {}", profile))),
}
println!(
"cargo:rustc-link-search=native={}",
dst.join("lib").display()
);
println!(
"cargo:rustc-link-search=native={}",
dst.join("lib64").display()
);
println!("cargo:rustc-link-lib=static=zstd");
}
#[cfg(feature = "dynamic")]
{
println!( println!(
"cargo:rustc-link-search=native={}", "cargo:rustc-link-search=native={}",
dst.join("build/Src/libCZIAPI").display() dst.join("build/Src/libCZIAPI").display()
); );
println!("cargo:rustc-link-lib=libCZIAPI"); println!("cargo:rustc-link-lib=libCZIAPI");
} }
}
println!("cargo::rerun-if-changed=build.rs"); println!("cargo::rerun-if-changed=build.rs");
Ok(()) Ok(())
} }
#[cfg(not(feature = "dynamic"))]
#[derive(Debug)]
struct DeMangler {
map: HashMap<String, String>,
}
#[cfg(not(feature = "dynamic"))]
impl DeMangler {
fn new(a_file: PathBuf) -> Result<Self> {
let cmd = std::process::Command::new("nm").arg(&a_file).output()?;
let pat = Regex::new(r"^[\da-f]*\s[A-Z]\s(.*_Z(\d+)(libCZI_.*))$")?;
let mut map = HashMap::new();
for line in std::str::from_utf8(&cmd.stdout)?.lines() {
if let Some(caps) = pat.captures(line.trim()) {
if let (Some(symbol), Some(n), Some(name)) = (caps.get(1), caps.get(2), caps.get(3))
{
let n: usize = n.as_str().parse()?;
let name = name.as_str();
let demangled = name[..n].to_string();
let mangled = symbol.as_str().to_string();
if let Some(existing_mangled) = map.get(&demangled) {
if existing_mangled != &mangled {
return Err(Error::msg(format!(
"conflicting mangled symbols for {} in {}: {}, {}",
demangled,
a_file.to_str().unwrap(),
existing_mangled,
mangled
)));
}
} else {
map.insert(demangled, mangled);
}
}
}
}
Ok(Self { map })
}
}
#[cfg(not(feature = "dynamic"))]
impl bindgen::callbacks::ParseCallbacks for DeMangler {
fn generated_link_name_override(&self, item_info: ItemInfo<'_>) -> Option<String> {
self.map.get(item_info.name).cloned()
}
}

1
libczi Submodule

Submodule libczi added at 494ac62f85

View File

@@ -640,7 +640,13 @@ impl LockedBitmap {
/// \\param \[out\] ptr Pointer to the memory location where the bitmap is to be copied to. /// \\param \[out\] ptr Pointer to the memory location where the bitmap is to be copied to.
/// ///
/// \\returns A LibCZIApiErrorCode. /// \\returns A LibCZIApiErrorCode.
pub fn copy(&self, width: u32, height: u32, pixel_type: PixelType, stride: u32) -> Result<Bitmap> { pub fn copy(
&self,
width: u32,
height: u32,
pixel_type: PixelType,
stride: u32,
) -> Result<Bitmap> {
let mut data = MaybeUninit::<Self>::uninit(); let mut data = MaybeUninit::<Self>::uninit();
LibCZIApiError::try_from(unsafe { LibCZIApiError::try_from(unsafe {
libCZI_BitmapCopyTo( libCZI_BitmapCopyTo(

View File

@@ -3,7 +3,6 @@ use crate::sys::*;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::ops::Deref; use std::ops::Deref;
/// CZI-reader object. /// CZI-reader object.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct CziReader(pub(crate) CziReaderObjectHandle); pub struct CziReader(pub(crate) CziReaderObjectHandle);
@@ -44,7 +43,9 @@ pub struct CziWriter(pub (crate) CziWriterObjectHandle);
/// single-channel-scaling-tile-accessor. /// single-channel-scaling-tile-accessor.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SingleChannelScalingTileAccessor(pub (crate) SingleChannelScalingTileAccessorObjectHandle); pub struct SingleChannelScalingTileAccessor(
pub(crate) SingleChannelScalingTileAccessorObjectHandle,
);
/// document info object. /// document info object.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]

View File

@@ -488,8 +488,83 @@ impl SubBlockStatistics {
} }
} }
impl SubBlockStatisticsEx {
// pub fn new(
// sub_block_count: i32,
// min_m_index: i32,
// max_m_index: i32,
// bounding_box: IntRect,
// bounding_box_layer0: IntRect,
// dim_bounds: DimBounds,
// per_scenes_bounding_boxes: Vec<BoundingBoxes>
// ) -> Self {
// Self(SubBlockStatisticsInteropEx {
// sub_block_count,
// min_m_index,
// max_m_index,
// bounding_box: bounding_box.0,
// bounding_box_layer0: bounding_box_layer0.0,
// dim_bounds: dim_bounds.0,
// number_of_per_scenes_bounding_boxes: per_scenes_bounding_boxes.len() as i32,
// per_scenes_bounding_boxes: unsafe { transmute::<Vec<BoundingBoxes>, __IncompleteArrayField<BoundingBoxesInterop>>(per_scenes_bounding_boxes) },
// })
// }
pub fn get_sub_block_count(&self) -> i32 {
self.0.sub_block_count
}
pub fn get_min_m_index(&self) -> i32 {
self.0.min_m_index
}
pub fn get_max_m_index(&self) -> i32 {
self.0.max_m_index
}
pub fn get_bounding_box(&self) -> IntRect {
IntRect(self.0.bounding_box)
}
pub fn get_bounding_box_layer0(&self) -> IntRect {
IntRect(self.0.bounding_box_layer0)
}
pub fn get_dim_bounds(&self) -> DimBounds {
DimBounds(self.0.dim_bounds)
}
pub fn get_number_of_per_scenes_bounding_boxes(&self) -> i32 {
self.0.number_of_per_scenes_bounding_boxes
}
// pub fn get_per_scenes_bounding_boxes(&self) -> Vec<BoundingBoxes> {
// unsafe { transmute(&self.0.per_scenes_bounding_boxes) }.clone()
// }
pub fn set_sub_block_count(&mut self, sub_block_count: i32) {
self.0.sub_block_count = sub_block_count;
}
pub fn set_min_m_index(&mut self, min_m_index: i32) {
self.0.min_m_index = min_m_index;
}
pub fn set_max_m_index(&mut self, max_m_index: i32) {
self.0.max_m_index = max_m_index;
}
pub fn set_bounding_box(&mut self, bounding_box: IntRect) {
self.0.bounding_box = bounding_box.0
}
pub fn set_bounding_box_layer0(&mut self, bounding_box_layer0: IntRect) {
self.0.bounding_box_layer0 = bounding_box_layer0.0
}
pub fn set_dim_bounds(&mut self, dim_bounds: DimBounds) {
self.0.dim_bounds = dim_bounds.0
}
pub fn set_number_of_per_scenes_bounding_boxes(
&mut self,
number_of_per_scenes_bounding_boxes: i32,
) {
self.0.number_of_per_scenes_bounding_boxes = number_of_per_scenes_bounding_boxes;
}
// pub fn set_per_scenes_bounding_boxes(&mut self, per_scenes_bounding_boxes: Vec<BoundingBoxes>) {
// self.0.number_of_per_scenes_bounding_boxes = per_scenes_bounding_boxes.len() as i32;
// self.0.per_scenes_bounding_boxes = unsafe { transmute(per_scenes_bounding_boxes) };
// }
}
impl MetadataAsXml { impl MetadataAsXml {
fn get_data(&self) -> Result<String> { pub fn get_data(&self) -> Result<String> {
let xml_data = unsafe { let xml_data = unsafe {
Vec::from_raw_parts( Vec::from_raw_parts(
self.0.data as *mut u8, self.0.data as *mut u8,
@@ -697,12 +772,8 @@ impl AddSubBlockInfo {
physical_height: i32, physical_height: i32,
pixel_type: PixelType, pixel_type: PixelType,
compression_mode_raw: i32, compression_mode_raw: i32,
size_data: u32,
data: &[u8], data: &[u8],
stride: u32,
size_metadata: u32,
metadata: &[u8], metadata: &[u8],
size_attachment: u32,
attachment: &[u8], attachment: &[u8],
) -> Self { ) -> Self {
let data = ManuallyDrop::new(data.to_vec()); let data = ManuallyDrop::new(data.to_vec());
@@ -721,12 +792,12 @@ impl AddSubBlockInfo {
physical_height, physical_height,
pixel_type: pixel_type.into(), pixel_type: pixel_type.into(),
compression_mode_raw, compression_mode_raw,
size_data, size_data: data.len() as u32,
data: data.as_ptr() as *const c_void, data: data.as_ptr() as *const c_void,
stride, stride: 1,
size_metadata, size_metadata: metadata.len() as u32,
metadata: metadata.as_ptr() as *const c_void, metadata: metadata.as_ptr() as *const c_void,
size_attachment, size_attachment: attachment.len() as u32,
attachment: attachment.as_ptr() as *const c_void, attachment: attachment.as_ptr() as *const c_void,
}) })
} }
@@ -832,25 +903,16 @@ impl AddSubBlockInfo {
pub fn set_compression_mode_raw(&mut self, compression_mode_raw: i32) { pub fn set_compression_mode_raw(&mut self, compression_mode_raw: i32) {
self.0.compression_mode_raw = compression_mode_raw self.0.compression_mode_raw = compression_mode_raw
} }
pub fn set_size_data(&mut self, size_data: u32) {
self.0.size_data = size_data
}
pub fn set_data(&mut self, data: &[u8]) { pub fn set_data(&mut self, data: &[u8]) {
let data = ManuallyDrop::new(data.to_vec()); let data = ManuallyDrop::new(data.to_vec());
self.0.data = data.as_ptr() as *const c_void; self.0.data = data.as_ptr() as *const c_void;
self.0.size_data = data.len() as u32; self.0.size_data = data.len() as u32;
} }
pub fn set_size_metadata(&mut self, size_metadata: u32) {
self.0.size_metadata = size_metadata
}
pub fn set_metadata(&mut self, metadata: &[u8]) { pub fn set_metadata(&mut self, metadata: &[u8]) {
let metadata = ManuallyDrop::new(metadata.to_vec()); let metadata = ManuallyDrop::new(metadata.to_vec());
self.0.metadata = metadata.as_ptr() as *const c_void; self.0.metadata = metadata.as_ptr() as *const c_void;
self.0.size_metadata = metadata.len() as u32; self.0.size_metadata = metadata.len() as u32;
} }
pub fn set_size_attachment(&mut self, size_attachment: u32) {
self.0.size_attachment = size_attachment
}
pub fn set_attachment(&mut self, attachment: &[u8]) { pub fn set_attachment(&mut self, attachment: &[u8]) {
let attachment = ManuallyDrop::new(attachment.to_vec()); let attachment = ManuallyDrop::new(attachment.to_vec());
self.0.attachment = attachment.as_ptr() as *const c_void; self.0.attachment = attachment.as_ptr() as *const c_void;
@@ -863,7 +925,6 @@ impl AddAttachmentInfo {
guid: [u8; 16], guid: [u8; 16],
content_file_type: [u8; 8], content_file_type: [u8; 8],
name: [u8; 80], name: [u8; 80],
size_attachment_data: u32,
attachment_data: &[u8], attachment_data: &[u8],
) -> Self { ) -> Self {
let attachment_data = ManuallyDrop::new(attachment_data.to_vec()); let attachment_data = ManuallyDrop::new(attachment_data.to_vec());
@@ -871,7 +932,7 @@ impl AddAttachmentInfo {
guid, guid,
contentFileType: content_file_type, contentFileType: content_file_type,
name, name,
size_attachment_data, size_attachment_data: attachment_data.len() as u32,
attachment_data: attachment_data.as_ptr() as *const c_void, attachment_data: attachment_data.as_ptr() as *const c_void,
}) })
} }
@@ -905,9 +966,6 @@ impl AddAttachmentInfo {
pub fn set_name(&mut self, name: [u8; 80]) { pub fn set_name(&mut self, name: [u8; 80]) {
self.0.name = name self.0.name = name
} }
pub fn set_size_attachment_data(&mut self, size_attachment_data: u32) {
self.0.size_attachment_data = size_attachment_data
}
pub fn set_attachment_data(&mut self, attachment_data: &[u8]) { pub fn set_attachment_data(&mut self, attachment_data: &[u8]) {
let attachment_data = ManuallyDrop::new(attachment_data.to_vec()); let attachment_data = ManuallyDrop::new(attachment_data.to_vec());
self.0.attachment_data = attachment_data.as_ptr() as *const c_void; self.0.attachment_data = attachment_data.as_ptr() as *const c_void;
@@ -916,10 +974,10 @@ impl AddAttachmentInfo {
} }
impl WriteMetadataInfo { impl WriteMetadataInfo {
pub fn new(size_metadata: u32, metadata: &[u8]) -> Self { pub fn new(metadata: &[u8]) -> Self {
let metadata = ManuallyDrop::new(metadata.to_vec()); let metadata = ManuallyDrop::new(metadata.to_vec());
Self(WriteMetadataInfoInterop { Self(WriteMetadataInfoInterop {
size_metadata, size_metadata: metadata.len() as u32,
metadata: metadata.as_ptr() as *const c_void, metadata: metadata.as_ptr() as *const c_void,
}) })
} }
@@ -935,9 +993,6 @@ impl WriteMetadataInfo {
) )
} }
} }
pub fn set_size_metadata(&mut self, size_metadata: u32) {
self.0.size_metadata = size_metadata
}
pub fn set_metadata(&mut self, metadata: &[u8]) { pub fn set_metadata(&mut self, metadata: &[u8]) {
let metadata = ManuallyDrop::new(metadata.to_vec()); let metadata = ManuallyDrop::new(metadata.to_vec());
self.0.metadata = metadata.as_ptr() as *const c_void; self.0.metadata = metadata.as_ptr() as *const c_void;

View File

@@ -1,3 +1,5 @@
extern crate link_cplusplus;
mod functions; mod functions;
mod handle; mod handle;
mod interop; mod interop;
@@ -7,7 +9,7 @@ pub mod sys;
pub use functions::*; pub use functions::*;
pub use handle::*; pub use handle::*;
pub use interop::*; pub use interop::*;
pub use misc::{LibCZIApiError, RawDataType, PixelType}; pub use misc::{LibCZIApiError, PixelType, RawDataType};
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@@ -15,6 +17,7 @@ mod tests {
use crate::interop::{LibCZIBuildInformation, ReaderOpenInfo}; use crate::interop::{LibCZIBuildInformation, ReaderOpenInfo};
use anyhow::{Error, Result}; use anyhow::{Error, Result};
use std::env; use std::env;
use std::path::PathBuf;
#[test] #[test]
fn test_libczi_xml() -> Result<()> { fn test_libczi_xml() -> Result<()> {
@@ -37,9 +40,7 @@ mod tests {
#[test] #[test]
fn test_libczi_pyramid_statistics() -> Result<()> { fn test_libczi_pyramid_statistics() -> Result<()> {
let path = env::home_dir() let path = PathBuf::from("test-files/Experiment-2029.czi");
.unwrap()
.join("code/rust/ndbioimage/tests/files/Experiment-2029.czi");
assert!(path.exists()); assert!(path.exists());
let czi = CziReader::create()?; let czi = CziReader::create()?;
let stream = InputStream::create_from_file_utf8( let stream = InputStream::create_from_file_utf8(
@@ -54,9 +55,7 @@ mod tests {
#[test] #[test]
fn test_libczi_document_info() -> Result<()> { fn test_libczi_document_info() -> Result<()> {
let path = env::home_dir() let path = PathBuf::from("test-files/Experiment-2029.czi");
.unwrap()
.join("code/rust/ndbioimage/tests/files/Experiment-2029.czi");
assert!(path.exists()); assert!(path.exists());
let czi = CziReader::create()?; let czi = CziReader::create()?;
let stream = InputStream::create_from_file_utf8( let stream = InputStream::create_from_file_utf8(
@@ -67,16 +66,25 @@ mod tests {
let metadata_segment = czi.get_metadata_segment()?; let metadata_segment = czi.get_metadata_segment()?;
let document_info = metadata_segment.get_czi_document_info()?; let document_info = metadata_segment.get_czi_document_info()?;
let general_document_info = document_info.get_general_document_info()?; let general_document_info = document_info.get_general_document_info()?;
println!("xml: {}", &general_document_info[..general_document_info.len().min(100)]); println!(
"xml: {}",
&general_document_info[..general_document_info.len().min(100)]
);
Ok(()) Ok(())
} }
#[test] #[test]
fn test_lib_czi_build_information() -> Result<()> { fn test_lib_czi_build_information() -> Result<()> {
let build_info = LibCZIBuildInformation::get()?; let build_info = LibCZIBuildInformation::get()?;
println!("compiler information: {:?}", build_info.get_compiler_information()); println!(
"compiler information: {:?}",
build_info.get_compiler_information()
);
println!("repository url: {:?}", build_info.get_repository_url()); println!("repository url: {:?}", build_info.get_repository_url());
println!("repository branch: {:?}", build_info.get_repository_branch()); println!(
"repository branch: {:?}",
build_info.get_repository_branch()
);
println!("repository tag: {:?}", build_info.get_repository_tag()); println!("repository tag: {:?}", build_info.get_repository_tag());
Ok(()) Ok(())
} }

View File

@@ -1,4 +1,4 @@
use anyhow::{anyhow, Error, Result}; use anyhow::{Error, Result, anyhow};
use std::fmt; use std::fmt;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::os::raw::c_int; use std::os::raw::c_int;

View File

@@ -7,4 +7,8 @@
#![allow(rustdoc::invalid_html_tags)] #![allow(rustdoc::invalid_html_tags)]
#![allow(clippy::missing_safety_doc)] #![allow(clippy::missing_safety_doc)]
#[cfg(docsrs)]
include!("lib_czi_api.rs"); include!("lib_czi_api.rs");
#[cfg(not(docsrs))]
include!(concat!(env!("OUT_DIR"), "/lib_czi_api.rs"));

Binary file not shown.