9 releases

0.2.7 Jan 20, 2022
0.2.6 Oct 18, 2021
0.1.0 Oct 13, 2021

#266 in Unix APIs

Download history 378/week @ 2023-12-06 156/week @ 2023-12-13 133/week @ 2023-12-20 409/week @ 2023-12-27 360/week @ 2024-01-03 108/week @ 2024-01-10 230/week @ 2024-01-17 218/week @ 2024-01-24 78/week @ 2024-01-31 15/week @ 2024-02-07 43/week @ 2024-02-14 74/week @ 2024-02-21 104/week @ 2024-02-28 42/week @ 2024-03-06 63/week @ 2024-03-13 112/week @ 2024-03-20

336 downloads per month
Used in stromatekt

MIT license

383 lines

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.


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().


Creating an UnixString with bytes received through FFI

use libc::{c_char, getcwd};
use unixstring::UnixString;

fn main() {
    const PATH_SIZ: usize = 1024;
    let mut buf: [c_char; 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

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

use unixstring::UnixString;

fn stat(path: &UnixString) -> std::io::Result<libc::stat> {
    // 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();
    } else {

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

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