Skip to content

Commit 4f61894

Browse files
committed
Add FFI for str2space, rename convert_space FFIs
Rename `convert_space_ffi_3f32` -> `convert_space_3f32` along with other monotypes. This is because the functions aren't publicly exposed in Rust, so the `_ffi` qualifier is just excess Add `str2space_ffi` generic function and appropriate monotypes `impl TryFrom<*const c_char> for Space` to share code between FFIs
1 parent d1abda4 commit 4f61894

File tree

2 files changed

+70
-39
lines changed

2 files changed

+70
-39
lines changed

scripts/test_ctypes.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,16 @@
1414

1515
colcon = ctypes.CDLL(f"./target/release/{LIBRARY}")
1616

17-
colcon.convert_space_ffi_3f32.argtypes = [
17+
colcon.convert_space_3f32.argtypes = [
1818
ctypes.c_char_p,
1919
ctypes.c_char_p,
2020
cpixels,
2121
ctypes.c_uint,
2222
]
23-
colcon.convert_space_ffi_3f32.restype = ctypes.c_int32
23+
colcon.convert_space_3f32.restype = ctypes.c_int32
24+
25+
colcon.str2space_3f32.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
26+
colcon.str2space_3f32.restype = cpixels # No way to have a known size?
2427

2528
# up
2629
colcon.srgb_to_hsv_3f32.argtypes = [cpixel]
@@ -141,6 +144,11 @@ def pixcmp(a, b):
141144
pixcmp(list(pix), HSV)
142145

143146
pix = (ctypes.c_float * len(SRGB))(*SRGB)
144-
if colcon.convert_space_ffi_3f32("srgb".encode(), "lch".encode(), pix, len(pix)) != 0:
147+
if colcon.convert_space_3f32("srgb".encode(), "lch".encode(), pix, len(pix)) != 0:
145148
print("CONVERT SPACE FAIL")
146149
pixcmp(list(pix), LCH)
150+
151+
pix = colcon.str2space_3f32(f"oklab {OKLAB}".encode(), "srgb".encode())
152+
pixcmp(pix[0:3], SRGB)
153+
# validate null is utilized
154+
assert not bool(colcon.str2space_3f32("cheese sandwhich".encode(), "srgb".encode()))

src/lib.rs

+59-36
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ pub trait DType:
7575
+ Rem<Output = Self>
7676
+ Sub<Output = Self>
7777
+ PartialOrd
78+
+ Debug
7879
+ Display
7980
+ FromF32
8081
{
@@ -558,6 +559,22 @@ impl TryFrom<&str> for Space {
558559
}
559560
}
560561

562+
impl TryFrom<*const c_char> for Space {
563+
type Error = ();
564+
fn try_from(value: *const c_char) -> Result<Self, ()> {
565+
if value.is_null() {
566+
Err(())
567+
} else {
568+
unsafe { CStr::from_ptr(value) }
569+
.to_str()
570+
.ok()
571+
.map(|s| Self::try_from(s).ok())
572+
.flatten()
573+
.ok_or(())
574+
}
575+
}
576+
}
577+
561578
impl Display for Space {
562579
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
563580
core::fmt::write(
@@ -755,38 +772,8 @@ pub fn convert_space_ffi<T: DType, const N: usize>(
755772
where
756773
Channels<N>: ValidChannels,
757774
{
758-
let from = unsafe {
759-
if from.is_null() {
760-
return 1;
761-
} else {
762-
if let Some(s) = CStr::from_ptr(from)
763-
.to_str()
764-
.ok()
765-
.map(|s| Space::try_from(s).ok())
766-
.flatten()
767-
{
768-
s
769-
} else {
770-
return 1;
771-
}
772-
}
773-
};
774-
let to = unsafe {
775-
if to.is_null() {
776-
return 2;
777-
} else {
778-
if let Some(s) = CStr::from_ptr(to)
779-
.to_str()
780-
.ok()
781-
.map(|s| Space::try_from(s).ok())
782-
.flatten()
783-
{
784-
s
785-
} else {
786-
return 2;
787-
}
788-
}
789-
};
775+
let Ok(from) = Space::try_from(from) else { return 1 };
776+
let Ok(to) = Space::try_from(to) else { return 2 };
790777
let pixels = unsafe {
791778
if pixels.is_null() {
792779
return 3;
@@ -905,6 +892,25 @@ where
905892
col
906893
})
907894
}
895+
896+
/// Same as `str2space` but with FFI types
897+
///
898+
/// Returns an N-length pointer to T on success or null on failure
899+
pub fn str2space_ffi<T: DType, const N: usize>(s: *const c_char, to: *const c_char) -> *const T
900+
where
901+
Channels<N>: ValidChannels,
902+
{
903+
if s.is_null() {
904+
return core::ptr::null();
905+
};
906+
let Some(s) = unsafe { CStr::from_ptr(s) }.to_str().ok() else {
907+
return core::ptr::null();
908+
};
909+
let Ok(to) = Space::try_from(to) else {
910+
return core::ptr::null();
911+
};
912+
str2space::<T, N>(s, to).map_or(core::ptr::null(), |b| Box::into_raw(Box::new(b)).cast())
913+
}
908914
// ### Str2Col ### }}}
909915

910916
// ### FORWARD ### {{{
@@ -1316,22 +1322,39 @@ where
13161322
// ### MONOTYPED EXTERNAL FUNCTIONS ### {{{
13171323

13181324
#[no_mangle]
1319-
extern "C" fn convert_space_ffi_3f32(from: *const c_char, to: *const c_char, pixels: *mut f32, len: usize) -> i32 {
1325+
extern "C" fn convert_space_3f32(from: *const c_char, to: *const c_char, pixels: *mut f32, len: usize) -> i32 {
13201326
convert_space_ffi::<_, 3>(from, to, pixels, len)
13211327
}
13221328
#[no_mangle]
1323-
extern "C" fn convert_space_ffi_4f32(from: *const c_char, to: *const c_char, pixels: *mut f32, len: usize) -> i32 {
1329+
extern "C" fn convert_space_4f32(from: *const c_char, to: *const c_char, pixels: *mut f32, len: usize) -> i32 {
13241330
convert_space_ffi::<_, 4>(from, to, pixels, len)
13251331
}
13261332
#[no_mangle]
1327-
extern "C" fn convert_space_ffi_3f64(from: *const c_char, to: *const c_char, pixels: *mut f64, len: usize) -> i32 {
1333+
extern "C" fn convert_space_3f64(from: *const c_char, to: *const c_char, pixels: *mut f64, len: usize) -> i32 {
13281334
convert_space_ffi::<_, 3>(from, to, pixels, len)
13291335
}
13301336
#[no_mangle]
1331-
extern "C" fn convert_space_ffi_4f64(from: *const c_char, to: *const c_char, pixels: *mut f64, len: usize) -> i32 {
1337+
extern "C" fn convert_space_4f64(from: *const c_char, to: *const c_char, pixels: *mut f64, len: usize) -> i32 {
13321338
convert_space_ffi::<_, 4>(from, to, pixels, len)
13331339
}
13341340

1341+
#[no_mangle]
1342+
extern "C" fn str2space_3f32(s: *const c_char, to: *const c_char) -> *const f32 {
1343+
str2space_ffi::<f32, 3>(s, to)
1344+
}
1345+
#[no_mangle]
1346+
extern "C" fn str2space_4f32(s: *const c_char, to: *const c_char) -> *const f32 {
1347+
str2space_ffi::<f32, 4>(s, to)
1348+
}
1349+
#[no_mangle]
1350+
extern "C" fn str2space_3f64(s: *const c_char, to: *const c_char) -> *const f64 {
1351+
str2space_ffi::<f64, 3>(s, to)
1352+
}
1353+
#[no_mangle]
1354+
extern "C" fn str2space_4f64(s: *const c_char, to: *const c_char) -> *const f64 {
1355+
str2space_ffi::<f64, 4>(s, to)
1356+
}
1357+
13351358
macro_rules! cdef1 {
13361359
($base:ident, $f32:ident, $f64:ident) => {
13371360
#[no_mangle]

0 commit comments

Comments
 (0)