Skip to content

Commit

Permalink
[feat] Add a rust type to c++ class wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
uttarayan21 committed Jan 11, 2024
1 parent ed0751a commit 17cd116
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 53 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ default = ["exif"]

[build-dependencies]
anyhow = "1.0.58"
cbindgen = "0.26.0"
cc = "1.0.73"

[dev-dependencies]
Expand Down
38 changes: 38 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ fn main() -> anyhow::Result<()> {
#[cfg(feature = "exif")]
libread(out_dir)?;

riio(out_dir)?;

Ok(())
}

Expand Down Expand Up @@ -35,3 +37,39 @@ pub fn libread(out_dir: impl AsRef<Path>) -> anyhow::Result<()> {

Ok(())
}

pub fn riio(out_dir: impl AsRef<Path>) -> anyhow::Result<()> {
println!("cargo:rerun-if-changed=src/io.rs");
cbindgen::Builder::new()
.with_crate(env!("CARGO_MANIFEST_DIR"))
.with_language(cbindgen::Language::C)
.with_no_includes()
.with_header("#include<stdint.h>")
.with_include_guard("RUST_IO_H")
.generate()
.expect("Unable to generate bindings")
.write_to_file("io/io.h");

let includes = std::env::var("DEP_RAW_R_INCLUDE")?;
let includes = std::env::split_paths(&includes).collect::<Vec<_>>();
let mut riio = cc::Build::new();
riio.includes(includes)
.cpp(true)
.file("io/io.cpp")
.static_flag(true)
.shared_flag(false);

#[cfg(windows)]
riio.static_crt(true);

riio.compile("riio");

println!("cargo:rerun-if-changed=io/io.cpp");
println!("cargo:rustc-link-lib=static=riio");
println!(
"cargo:rustc-link-search=native={}",
out_dir.as_ref().join("lib").display()
);

Ok(())
}
18 changes: 18 additions & 0 deletions io/io.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "io.h"
#include <libraw.h>

class LibrawIO : public LibRaw_abstract_datastream {
public:
virtual ~LibrawIO() {}

virtual int valid() { return lod_valid(inner); }
virtual int read(void *ptr, size_t size, size_t nmemb) {
return lod_read(inner, ptr, size, nmemb);
}
virtual int seek(INT64 o, int whence) { return lod_seek(inner, o, whence); }
virtual INT64 tell() { return lod_tell(inner); }
virtual INT64 size() { return lod_size(inner); }

protected:
LibrawOpaqueDatastream *inner;
};
27 changes: 27 additions & 0 deletions io/io.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include<stdint.h>

#ifndef RUST_IO_H
#define RUST_IO_H



typedef struct LibrawOpaqueDatastream LibrawOpaqueDatastream;

int32_t lod_valid(struct LibrawOpaqueDatastream *this_);

int32_t lod_read(struct LibrawOpaqueDatastream *this_,
const void *buffer,
uintptr_t sz,
uintptr_t nmemb);

int32_t lod_seek(struct LibrawOpaqueDatastream *this_, int64_t offset, uint32_t whence);

int64_t lod_tell(struct LibrawOpaqueDatastream *this_);

int64_t lod_size(struct LibrawOpaqueDatastream *this_);

int lod_get_char(struct LibrawOpaqueDatastream *this_);

const char *lod_gets(struct LibrawOpaqueDatastream *this_, char *buffer, int size);

#endif /* RUST_IO_H */
179 changes: 126 additions & 53 deletions src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,19 @@
// #endif
// };
// ```
pub trait LibrawDatastream: Read + Seek + Sized {
pub trait LibrawDatastream: Read + Seek + Eof {
/// # Safety
///
/// This function will be called from ffi (c++)
/// This function is unsafe because it dereferences `this` ( self )
unsafe fn read(this: *mut Self, buffer: *const libc::c_void, sz: usize, nmemb: usize) -> i32 {
assert!(!this.is_null());
let this = &mut *this;
unsafe fn read(&mut self, buffer: *const libc::c_void, sz: usize, nmemb: usize) -> i32 {
// assert!(!this.is_null());
// let this = &mut *this;
let to_read = sz * nmemb;
if to_read < 1 {
return 0;
}
if this
if self
.read_exact(core::slice::from_raw_parts_mut(
buffer.cast::<u8>().cast_mut(),
to_read,
Expand All @@ -134,82 +134,82 @@ pub trait LibrawDatastream: Read + Seek + Sized {
/// # Safety
///
/// Sus
unsafe fn seek(this: *mut Self, offset: i64, whence: u32) -> i32 {
assert!(!this.is_null());
let this = unsafe { &mut *this };
unsafe fn seek(&mut self, offset: i64, whence: u32) -> i32 {
// assert!(!this.is_null());
// let this = unsafe { &mut *this };
match whence {
sys::SEEK_SET => this.seek(std::io::SeekFrom::Start(offset as u64)).ok(),
sys::SEEK_CUR => this.seek(std::io::SeekFrom::Current(offset)).ok(),
sys::SEEK_END => this.seek(std::io::SeekFrom::End(offset)).ok(),
sys::SEEK_SET => {
std::io::Seek::seek(self, std::io::SeekFrom::Start(offset as u64)).ok()
}
sys::SEEK_CUR => std::io::Seek::seek(self, std::io::SeekFrom::Current(offset)).ok(),
sys::SEEK_END => std::io::Seek::seek(self, std::io::SeekFrom::End(offset)).ok(),
_ => return 0,
};
0
}
/// # Safety
///
/// This function is unsafe because it dereferences a raw pointer.
unsafe fn tell(this: *mut Self) -> i64 {
assert!(!this.is_null());
let this = unsafe { &mut *this };
this.stream_position().map(|f| f as i64).unwrap_or(-1)
unsafe fn tell(&mut self) -> i64 {
// assert!(!this.is_null());
// let this = unsafe { &mut *this };
self.stream_position().map(|f| f as i64).unwrap_or(-1)
}
/// # Safety
///
/// This function is unsafe because it dereferences a raw pointer.
unsafe fn eof(this: *mut Self) -> i32 {
assert!(!this.is_null());
let this = unsafe { &mut *this };
<Self as Eof>::eof(this).map(|f| f as i32).unwrap_or(0) - 1
unsafe fn eof_(&mut self) -> i32 {
// assert!(!this.is_null());
// let this = unsafe { &mut *this };
Eof::eof(self).map(|f| f as i32).unwrap_or(0) - 1
}

/// # Safety
///
/// This function is unsafe because it dereferences a raw pointer.
unsafe fn size(this: *mut Self) -> i64 {
assert!(!this.is_null());
let this = unsafe { &mut *this };
<Self as Eof>::len(this).map(|f| f as i64).unwrap_or(-1)
unsafe fn size(&mut self) -> i64 {
// assert!(!this.is_null());
// let this = unsafe { &mut *this };
Eof::len(self).map(|f| f as i64).unwrap_or(-1)
}

/// # Safety
///
/// Reads a char from the buffer and casts it as i32 and in case of error returns -1
unsafe fn get_char(this: *mut Self) -> libc::c_int {
assert!(!this.is_null());
let this = unsafe { &mut *this };
unsafe fn get_char(&mut self) -> libc::c_int {
// assert!(!this.is_null());
// let this = unsafe { &mut *this };
let mut buf = [0u8];
if this.read_exact(&mut buf).is_err() {
if self.read_exact(&mut buf).is_err() {
-1
} else {
buf[0] as libc::c_int
}
}
}

impl<T: Read + Seek + Eof> LibrawDatastream for T {}

pub trait LibrawBufferedDatastream: LibrawDatastream + BufRead {
/// # Safety
///
/// This function is unsafe because it dereferences a raw pointer and is called from ffi.
/// This function is like fgets(3)
/// The C++ function which wraps this
/// `char *LibRaw_buffer_datastream::gets(char *s, int sz)`
unsafe fn gets(
this: *mut Self,
buffer: *mut libc::c_char,
size: libc::c_int,
) -> *const libc::c_char {
unsafe fn gets(&mut self, buffer: *mut libc::c_char, size: libc::c_int) -> *const libc::c_char {
if size < 1 {
return core::ptr::null();
}
assert!(!this.is_null());
let this = unsafe { &mut *this };
if this.eof().unwrap_or(true) {
// assert!(!this.is_null());
// let this = unsafe { &mut *this };
if self.eof().unwrap_or(true) {
return core::ptr::null();
}
assert!(!buffer.is_null());
let size = size.clamp(u16::MAX.into(), u16::MIN.into()) as usize;
let buffer: &mut [u8] = core::slice::from_raw_parts_mut(buffer.cast(), size);
let x = read_until(this, b'\n', buffer);
let x = read_until(self, b'\n', buffer);
if x.is_err() {
return core::ptr::null();
}
Expand All @@ -223,6 +223,8 @@ pub trait LibrawBufferedDatastream: LibrawDatastream + BufRead {
}
}

impl<T: LibrawDatastream + BufRead> LibrawBufferedDatastream for T {}

use core::ops::{Deref, DerefMut};
// pub trait Libraw
use std::io::{BufRead, Read, Seek, Write};
Expand Down Expand Up @@ -262,6 +264,7 @@ impl<T: Seek> Eof for T {}
/// Abstract Datastream
///
/// Using the rust version of the abstract datastream
#[repr(C)]
pub struct AbstractDatastream<T: Read + Seek + Sized> {
inner: T,
}
Expand All @@ -272,31 +275,31 @@ impl<T: Read + Seek + Sized> AbstractDatastream<T> {
}
}

impl<T: Read + Seek + Sized> DerefMut for AbstractDatastream<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<T: Read + Seek + Sized> Deref for AbstractDatastream<T> {
type Target = T;

impl<T: Read + Seek + Sized> Read for AbstractDatastream<T> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.inner.read(buf)
fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl<T: Read + Seek + Sized> Seek for AbstractDatastream<T> {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
self.inner.seek(pos)
impl<T: Read + Seek + Sized> DerefMut for AbstractDatastream<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}

impl<T: Read + Seek + Sized> Deref for AbstractDatastream<T> {
type Target = T;
// impl<T: Read + Seek + Sized> Read for AbstractDatastream<T> {
// fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
// self.inner.read(buf)
// }
// }

fn deref(&self) -> &Self::Target {
&self.inner
}
}
// impl<T: Read + Seek + Sized> Seek for AbstractDatastream<T> {
// fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
// self.inner.seek(pos)
// }
// }

// Taken from rust's stdlib with some changes
fn read_until<R: BufRead + ?Sized>(
Expand Down Expand Up @@ -335,3 +338,73 @@ fn read_until<R: BufRead + ?Sized>(
}
}
}

// impl<T: LibrawBufferedDatastream> AbstractDatastream<T> {
#[repr(C)]
pub struct LibrawOpaqueDatastream {
inner: Box<dyn LibrawBufferedDatastream>,
}

impl LibrawOpaqueDatastream {
#[no_mangle]
pub unsafe extern "C" fn lod_valid(this: *mut Self) -> i32 {
assert!(!this.is_null());
let this = unsafe { &mut *this };
if this.inner.is_empty().unwrap_or(true) {
0
} else {
1
}
}

#[no_mangle]
pub unsafe extern "C" fn lod_read(
this: *mut Self,
buffer: *const libc::c_void,
sz: usize,
nmemb: usize,
) -> i32 {
assert!(!this.is_null());
let this = unsafe { &mut *this };
LibrawDatastream::read(&mut this.inner, buffer, sz, nmemb)
}

#[no_mangle]
pub unsafe extern "C" fn lod_seek(this: *mut Self, offset: i64, whence: u32) -> i32 {
assert!(!this.is_null());
let this = unsafe { &mut *this };
LibrawDatastream::seek(&mut this.inner, offset, whence)
}

#[no_mangle]
pub unsafe extern "C" fn lod_tell(this: *mut Self) -> i64 {
assert!(!this.is_null());
let this = unsafe { &mut *this };
LibrawDatastream::tell(&mut this.inner)
}

#[no_mangle]
pub unsafe extern "C" fn lod_size(this: *mut Self) -> i64 {
assert!(!this.is_null());
let this = unsafe { &mut *this };
LibrawDatastream::size(&mut this.inner)
}

#[no_mangle]
pub unsafe extern "C" fn lod_get_char(this: *mut Self) -> libc::c_int {
assert!(!this.is_null());
let this = unsafe { &mut *this };
LibrawDatastream::get_char(&mut this.inner)
}

#[no_mangle]
pub unsafe extern "C" fn lod_gets(
this: *mut Self,
buffer: *mut libc::c_char,
size: libc::c_int,
) -> *const libc::c_char {
assert!(!this.is_null());
let this = unsafe { &mut *this };
LibrawBufferedDatastream::gets(&mut this.inner, buffer, size)
}
}

0 comments on commit 17cd116

Please sign in to comment.