Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/vrmiguel/unixstring
An FFI-friendly null-terminated byte string
https://github.com/vrmiguel/unixstring
ffi hacktoberfest rust unix
Last synced: 3 months ago
JSON representation
An FFI-friendly null-terminated byte string
- Host: GitHub
- URL: https://github.com/vrmiguel/unixstring
- Owner: vrmiguel
- Created: 2021-10-13T05:40:07.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2022-01-20T01:41:23.000Z (about 3 years ago)
- Last Synced: 2024-09-14T09:44:04.441Z (5 months ago)
- Topics: ffi, hacktoberfest, rust, unix
- Language: Rust
- Homepage: https://crates.io/crates/unixstring
- Size: 116 KB
- Stars: 21
- Watchers: 2
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# unixstring [![codecov](https://codecov.io/gh/vrmiguel/unixstring/branch/master/graph/badge.svg?token=6rvhsF5Eiq)](https://codecov.io/gh/vrmiguel/unixstring) ![Crates.io](https://img.shields.io/crates/v/unixstring) [![Docs](https://img.shields.io/badge/docs.rs-unixstring-green)](https://docs.rs/unixstring/)
`UnixString` is an FFI-friendly null-terminated byte string that may be constructed from a [`String`](https://doc.rust-lang.org/std/string/struct.String.html), a [`CString`](https://doc.rust-lang.org/std/ffi/struct.CString.html), a [`PathBuf`](https://doc.rust-lang.org/std/path/struct.PathBuf.html), an [`OsString`](https://doc.rust-lang.org/std/ffi/struct.OsString.html) or a collection of bytes.
An [`UnixString`](UnixString) can then be converted into a slice of [`CStr`](https://doc.rust-lang.org/std/ffi/struct.CStr.html), [`Path`](https://doc.rust-lang.org/std/path/struct.Path.html) or [`OsStr`](https://doc.rust-lang.org/std/ffi/struct.OsStr.html) 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` | 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` | `UnixString::into_bytes` | Returns the bytes of the `UnixString` without the null terminator |
| `Vec` | `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 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
```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::args_os().map(UnixString::try_from).flatten() {
let stat = stat(&arg)?;
let size = stat.st_size;println!("{} occupies {} bytes.", arg.as_path().display(), size);
}Ok(())
}
```