unixstring codecov Crates.io Docs

UnixString is an FFI-friendly null-terminated byte string that may be constructed from a String, a CString, a PathBuf, an OsString or a collection of bytes.

An UnixString can then be converted into a slice of CStr, Path or OsStr in infallible and zero-cost operations.

Why?

UnixString aims to be useful in any scenario where you'd like to use FFI (specially with C) on Unix systems. If you have a PathBuf, for example, you can send that data to a libc function, such as stat, but you'd have to first allocate a CString (or something analogous) to do so.

The same is true with OsString and String because these three types are allowed to have internal zero bytes and are not null-terminated.

A UnixString is very close to what a CString is but with increased flexibility and usability. A CString cannot be changed or increased after instantited, while UnixString is growable through its push and push_bytes methods, somewhat similar to OsString.

A CString also does not have direct reference conversions to anything but &[u8] or &CStr, while UnixString has those and more (described below).

Obtaining references from an UnixString

| Into | Function | Notes | |:--------:|:-------------------------------:|:-----------------------------------------------------------------:| | &CStr | UnixString::as_c_str | Available through AsRef as well | | &Path | UnixString::as_path | Available through AsRef as well | | &str | UnixString::as_str | Fails if the bytes of the UnixString aren't valid UTF-8 | | &[u8] | UnixString::as_bytes | Returns the bytes of the UnixString without the null terminator | | &[u8] | UnixString::as_bytes_with_nul | Returns the bytes of the UnixString with the null terminator | | &OsStr | UnixString::as_os_str | Available through AsRef as well | | * const c_char | UnixString::as_ptr | |

Creating an UnixString

| From | Potential failure | Trait impl | Function | |:----------:|:---------------------------------------:|:----------:|:----------------------------:| | CString | Infallible | From | UnixString::from_cstring | | PathBuf | Fails if contains an interior zero byte | TryFrom | UnixString::from_pathbuf | | String | Fails if contains an interior zero byte | TryFrom | UnixString::from_string | | Vec<u8> | Fails if contains an interior zero byte | TryFrom | UnixString::from_bytes | | OsString | Fails if contains an interior zero byte | TryFrom | UnixString::from_os_string | | * const c_char | Unsafe, see the docs for more info| None | UnixString::from_ptr |

Converting from an UnixString

| Into | Function | Notes | |:----------:|:-----------------------------------:|:----------------------------------------------------------------------:| | CString | UnixString::into_cstring | | | PathBuf | UnixString::into_pathbuf | | | OsString | UnixString::into_os_string | | | String | UnixString::into_string | Fails if the UnixString's bytes are not valid UTF-8 | | String | UnixString::into_string_lossy | | | String | UnixString::to_string_lossy | Non-moving version of UnixString::into_string_lossy | | String | UnixString::into_string_unchecked | Unsafe: creates a String without checking if the bytes are valid UTF-8 | | Vec<u8> | UnixString::into_bytes | Returns the bytes of the UnixString without the null terminator | | Vec<u8> | UnixString::into_bytes_with_nul | Returns the bytes of the UnixString with the null terminator |

All of the above are also available through .into().

Examples

Creating an UnixString with bytes received through FFI

```rust= use libc::{c_char, getcwd}; use unixstring::UnixString;

fn main() { const PATHSIZ: usize = 1024; let mut buf: [cchar; 1024] = [0; 1024];

let ptr = &mut buf as *mut c_char;

unsafe { getcwd(ptr, PATH_SIZ) };

if ptr.is_null() {
    panic!("getcwd failed");
}

let unix_string = unsafe { UnixString::from_ptr(ptr as *const c_char) };

assert_eq!(unix_string.as_path(), std::env::current_dir().unwrap())

}

```

Using an UnixString to send bytes through FFI

```rust use std::{convert::TryFrom, env};

use unixstring::UnixString;

fn stat(path: &UnixString) -> std::io::Result { // Safety: The all-zero byte-pattern is a valid struct stat let mut stat_buf = unsafe { std::mem::zeroed() };

if -1 == unsafe { libc::lstat(path.as_ptr(), &mut stat_buf) } {
    let io_err = std::io::Error::last_os_error();
    Err(io_err)
} else {
    Ok(stat_buf)
}

}

fn main() -> std::io::Result<()>{ for arg in env::argsos().map(UnixString::tryfrom).flatten() { let stat = stat(&arg)?;

    let size = stat.st_size;

    println!("{} occupies {} bytes.", arg.as_path().display(), size);
}

Ok(())

} ```