diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2019-09-11 01:15:20 +0200 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2019-11-26 22:07:28 +0100 |
commit | f738cd4d976f4f72159bbcbfa7b451c33f0ea74a (patch) | |
tree | 2c20a500f84c967aec1f74bca4d2383c673e1b62 /nix-rust | |
parent | 8110b4ebb29174ecd4b22510da0285abf604b8a7 (diff) |
More Rust FFI adventures
We can now convert Rust Errors to C++ exceptions. At the Rust->C++ FFI
boundary, Result<T, Error> will cause Error to be converted to and
thrown as a C++ exception.
Diffstat (limited to 'nix-rust')
-rw-r--r-- | nix-rust/src/error.rs | 27 | ||||
-rw-r--r-- | nix-rust/src/lib.rs | 27 | ||||
-rw-r--r-- | nix-rust/src/tarfile.rs | 20 |
3 files changed, 60 insertions, 14 deletions
diff --git a/nix-rust/src/error.rs b/nix-rust/src/error.rs index 28d0abdef..a2003be6f 100644 --- a/nix-rust/src/error.rs +++ b/nix-rust/src/error.rs @@ -1,5 +1,30 @@ #[derive(Debug)] pub enum Error { + IOError(std::io::Error), Misc(String), - Foreign(libc::c_void), // == std::exception_ptr + Foreign(CppException), +} + +impl From<std::io::Error> for Error { + fn from(err: std::io::Error) -> Self { + Error::IOError(err) + } +} + +impl From<Error> for CppException { + fn from(err: Error) -> Self { + match err { + Error::Foreign(ex) => ex, + Error::Misc(s) => unsafe { make_error(&s) }, + Error::IOError(err) => unsafe { make_error(&err.to_string()) }, + } + } +} + +#[repr(C)] +#[derive(Debug)] +pub struct CppException(*const libc::c_void); // == std::exception_ptr* + +extern "C" { + fn make_error(s: &str) -> CppException; } diff --git a/nix-rust/src/lib.rs b/nix-rust/src/lib.rs index 192ca29e4..b6b0d746d 100644 --- a/nix-rust/src/lib.rs +++ b/nix-rust/src/lib.rs @@ -4,7 +4,30 @@ mod tarfile; pub use error::Error; +pub struct CBox<T> { + ptr: *mut libc::c_void, + phantom: std::marker::PhantomData<T>, +} + +impl<T> CBox<T> { + fn new(t: T) -> Self { + unsafe { + let size = std::mem::size_of::<T>(); + let ptr = libc::malloc(size); + eprintln!("PTR = {:?}, SIZE = {}", ptr, size); + *(ptr as *mut T) = t; // FIXME: probably UB + Self { + ptr, + phantom: std::marker::PhantomData, + } + } + } +} + #[no_mangle] -pub extern "C" fn unpack_tarfile(source: foreign::Source, dest_dir: &str) { - tarfile::unpack_tarfile(source, dest_dir).unwrap(); +pub extern "C" fn unpack_tarfile( + source: foreign::Source, + dest_dir: &str, +) -> CBox<Result<(), error::CppException>> { + CBox::new(tarfile::unpack_tarfile(source, dest_dir).map_err(|err| err.into())) } diff --git a/nix-rust/src/tarfile.rs b/nix-rust/src/tarfile.rs index 696118e4d..797aa5064 100644 --- a/nix-rust/src/tarfile.rs +++ b/nix-rust/src/tarfile.rs @@ -10,19 +10,19 @@ pub fn unpack_tarfile(source: Source, dest_dir: &str) -> Result<(), Error> { let mut tar = Archive::new(source); - for file in tar.entries().unwrap() { - let mut file = file.unwrap(); + for file in tar.entries()? { + let mut file = file?; - let dest_file = dest_dir.join(file.path().unwrap()); + let dest_file = dest_dir.join(file.path()?); - fs::create_dir_all(dest_file.parent().unwrap()).unwrap(); + fs::create_dir_all(dest_file.parent().unwrap())?; match file.header().entry_type() { tar::EntryType::Directory => { - fs::create_dir(dest_file).unwrap(); + fs::create_dir(dest_file)?; } tar::EntryType::Regular => { - let mode = if file.header().mode().unwrap() & libc::S_IXUSR == 0 { + let mode = if file.header().mode()? & libc::S_IXUSR == 0 { 0o666 } else { 0o777 @@ -31,13 +31,11 @@ pub fn unpack_tarfile(source: Source, dest_dir: &str) -> Result<(), Error> { .create(true) .write(true) .mode(mode) - .open(dest_file) - .unwrap(); - io::copy(&mut file, &mut f).unwrap(); + .open(dest_file)?; + io::copy(&mut file, &mut f)?; } tar::EntryType::Symlink => { - std::os::unix::fs::symlink(file.header().link_name().unwrap().unwrap(), dest_file) - .unwrap(); + std::os::unix::fs::symlink(file.header().link_name()?.unwrap(), dest_file)?; } t => return Err(Error::Misc(format!("unsupported tar entry type '{:?}'", t))), } |