//! Strings that are compatible wuth Unix-like operating systems. //! //! * [`UnixString`] and [`UnixStr`] are useful when you need to with Unix strings. //! Conversions between [`UnixString`], [`UnixStr`] and Rust strings work similarly //! to those for `CString` and `CStr`. //! //! * [`UnixString`] represents an owned string in Unix's preferred //! representation. //! //! * [`UnixStr`] represents a borrowed reference to a string in a format that //! can be passed to a Unix-lie operating system. It can be converted into //! a UTF-8 Rust string slice in a similar way to [`UnixString`]. //! //! # Conversions //! //! [`UnixStr`] implements two methods, [`from_bytes`] and [`as_bytes`]. //! These do inexpensive conversions from and to UTF-8 byte slices. //! //! Additionally, [`UnixString`] provides [`from_vec`] and [`into_vec`] methods //! that consume their arguments, and take or produce vectors of [`u8`]. //! //! [`UnixString`]: struct.UnixString.html //! [`UnixStr`]: struct.UnixStr.html //! [`from_vec`]: struct.UnixString.html#method.from_vec //! [`into_vec`]: struct.UnixString.html#method.into_vec //! [`from_bytes`]: struct.UnixStrExt.html#method.from_bytes //! [`as_bytes`]: struct.UnixStrExt.html#method.as_bytes
use core::cmp; use core::fmt; use core::hash::{Hash, Hasher}; use core::mem;
#[cfg(feature = "alloc")] use alloc::borrow::{Borrow, Cow, ToOwned}; #[cfg(feature = "alloc")] use alloc::boxed::Box; #[cfg(feature = "alloc")] use alloc::rc::Rc; #[cfg(feature = "alloc")] use alloc::string::String; #[cfg(feature = "alloc")] use alloc::sync::Arc; #[cfg(feature = "alloc")] use alloc::vec::Vec; #[cfg(feature = "alloc")] use core::ops; #[cfg(feature = "alloc")] use core::str::FromStr;
mod lossy;
mod sys; #[cfg(feature = "alloc")] use sys::Buf; use sys::Slice;
mod sys_common; use sys_common::AsInner; #[cfg(feature = "alloc")] use sys_common::{FromInner, IntoInner};
/// A type that can represent owned, mutable Unix strings, but is cheaply /// inter-convertible with Rust strings. /// /// The need for this type arises from the fact that: /// /// * On Unix systems, strings are often arbitrary sequences of non-zero /// bytes, in many cases interpreted as UTF-8. /// /// * In Rust, strings are always valid UTF-8, which may contain zeros. /// /// `UnixString` and [`UnixStr`] bridge this gap by simultaneously representing /// Rust and platform-native string values, and in particular allowing a Rust /// string to be converted into a “Unix” string with no cost if possible. /// A consequence of this is that `UnixString` instances are *not* `NULL` /// terminated; in order to pass to e.g., Unix system call, you should create /// a `CStr`. /// /// `UnixString` is to [`&UnixStr`] as `String` is to `&str`: the former /// in each pair are owned strings; the latter are borrowed references. /// /// Note, `UnixString` and [`UnixStr`] internally do not hold in the form native /// to the platform: `UnixString`s are stored as a sequence of 8-bit values. /// /// # Creating an `UnixString` /// /// **From a Rust string**: `UnixString` implements `From<String>`, so you can /// use `my_string.from` to create an `UnixString` from a normal Rust string. /// /// **From slices:** Just like you can start with an empty Rust [`String`] /// and then [`push_str`][String.push_str] `&str` sub-string slices into it, /// you can create an empty `UnixString` with the [`new`] method and then push /// string slices into it with the [`push`] method. /// /// # Extracting a borrowed reference to the whole OS string /// /// You can use the [`as_unix_str`] method to get a [`&UnixStr`] from /// a `UnixString`; this is effectively a borrowed reference to the whole /// string. /// /// # Conversions /// /// See the [module's toplevel documentation about conversions][conversions] /// for a discussion on the traits which `UnixString` implements for /// [conversions] from/to native representations. /// /// [`UnixStr`]: struct.UnixStr.html /// [`&UnixStr`]: struct.UnixStr.html /// [`CStr`]: struct.CStr.html /// [`new`]: #method.new /// [`push`]: #method.push /// [`as_unix_str`]: #method.as_unix_str /// [conversions]: index.html#conversions #[derive(Clone)] #[cfg(feature = "alloc")] pubstruct UnixString {
inner: Buf,
}
/// Borrowed reference to a Unix string (see [`UnixString`]). /// /// This type represents a borrowed reference to a string in Unix's preferred /// representation. /// /// `&UnixStr` is to [`UnixString`] as `&str` is to `String`: the former /// in each pair are borrowed references; the latter are owned strings. /// /// See the [module's toplevel documentation about conversions][conversions] /// for a discussion on the traits which `UnixStr` implements for [conversions] /// from/to native representations. /// /// [`UnixString`]: struct.UnixString.html /// [conversions]: index.html#conversions // FIXME: // `UnixStr::from_inner` current implementation relies on `UnixStr` being // layout-compatible with `Slice`. When attribute privacy is implemented, // `UnixStr` should be annotated as `#[repr(transparent)]`. Anyway, `UnixStr` // representation and layout are considered implementation detail, are // not documented and must not be relied upon. pubstruct UnixStr {
inner: Slice,
}
/// Converts to an [`UnixStr`] slice. /// /// [`UnixStr`]: struct.UnixStr.html /// /// # Examples /// /// ``` /// use unix_str::{UnixString, UnixStr}; /// /// let unix_string = UnixString::from("foo"); /// let unix_str = UnixStr::new("foo"); /// assert_eq!(unix_string.as_unix_str(), unix_str); /// ``` pubfn as_unix_str(&self) -> &UnixStr { self
}
/// Converts the `UnixString` into a `String` if it contains valid Unicode data. /// /// On failure, ownership of the original `UnixString` is returned. /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// /// let unix_string = UnixString::from("foo"); /// let string = unix_string.into_string(); /// assert_eq!(string, Ok(String::from("foo"))); /// ``` pubfn into_string(self) -> Result<String, UnixString> { self.inner
.into_string()
.map_err(|buf| UnixString { inner: buf })
}
/// Extends the string with the given [`&UnixStr`] slice. /// /// [`&UnixStr`]: struct.UnixStr.html /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// /// let mut unix_string = UnixString::from("foo"); /// unix_string.push("bar"); /// assert_eq!(&unix_string, "foobar"); /// ``` pubfn push<T: AsRef<UnixStr>>(&mutself, s: T) { self.inner.push_slice(&s.as_ref().inner)
}
/// Creates a new `UnixString` with the given capacity. /// /// The string will be able to hold exactly `capacity` length units of other /// OS strings without reallocating. If `capacity` is 0, the string will not /// allocate. /// /// See main `UnixString` documentation information about encoding. /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// /// let mut unix_string = UnixString::with_capacity(10); /// let capacity = unix_string.capacity(); /// /// // This push is done without reallocating /// unix_string.push("foo"); /// /// assert_eq!(capacity, unix_string.capacity()); /// ``` pubfn with_capacity(capacity: usize) -> Self { Self {
inner: Buf::with_capacity(capacity),
}
}
/// Truncates the `UnixString` to zero length. /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// /// let mut unix_string = UnixString::from("foo"); /// assert_eq!(&unix_string, "foo"); /// /// unix_string.clear(); /// assert_eq!(&unix_string, ""); /// ``` pubfn clear(&mutself) { self.inner.clear()
}
/// Returns the capacity this `UnixString` can hold without reallocating. /// /// See `UnixString` introduction for information about encoding. /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// /// let unix_string = UnixString::with_capacity(10); /// assert!(unix_string.capacity() >= 10); /// ``` pubfn capacity(&self) -> usize { self.inner.capacity()
}
/// Reserves capacity for at least `additional` more capacity to be inserted /// in the given `UnixString`. /// /// The collection may reserve more space to avoid frequent reallocations. /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// /// let mut s = UnixString::new(); /// s.reserve(10); /// assert!(s.capacity() >= 10); /// ``` pubfn reserve(&mutself, additional: usize) { self.inner.reserve(additional)
}
/// Reserves the minimum capacity for exactly `additional` more capacity to /// be inserted in the given `UnixString`. Does nothing if the capacity is /// already sufficient. /// /// Note that the allocator may give the collection more space than it /// requests. Therefore, capacity can not be relied upon to be precisely /// minimal. Prefer reserve if future insertions are expected. /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// /// let mut s = UnixString::new(); /// s.reserve_exact(10); /// assert!(s.capacity() >= 10); /// ``` pubfn reserve_exact(&mutself, additional: usize) { self.inner.reserve_exact(additional)
}
/// Shrinks the capacity of the `UnixString` to match its length. /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// /// let mut s = UnixString::from("foo"); /// /// s.reserve(100); /// assert!(s.capacity() >= 100); /// /// s.shrink_to_fit(); /// assert_eq!(3, s.capacity()); /// ``` pubfn shrink_to_fit(&mutself) { self.inner.shrink_to_fit()
}
/// Shrinks the capacity of the `UnixString` with a lower bound. /// /// The capacity will remain at least as large as both the length /// and the supplied value. /// /// Panics if the current capacity is smaller than the supplied /// minimum capacity. /// /// # Examples /// /// ``` /// #![feature(shrink_to)] /// use std::ffi::UnixString; /// /// let mut s = UnixString::from("foo"); /// /// s.reserve(100); /// assert!(s.capacity() >= 100); /// /// s.shrink_to(10); /// assert!(s.capacity() >= 10); /// s.shrink_to(0); /// assert!(s.capacity() >= 3); /// ``` #[inline] #[cfg(feature = "shrink_to")] pubfn shrink_to(&mutself, min_capacity: usize) { self.inner.shrink_to(min_capacity)
}
/// Converts this `UnixString` into a boxed [`UnixStr`]. /// /// [`UnixStr`]: struct.UnixStr.html /// /// # Examples /// /// ``` /// use unix_str::{UnixString, UnixStr}; /// /// let s = UnixString::from("hello"); /// /// let b: Box<UnixStr> = s.into_boxed_unix_str(); /// ``` pubfn into_boxed_unix_str(self) -> Box<UnixStr> { let rw = Box::into_raw(self.inner.into_box()) as *mut UnixStr; unsafe { Box::from_raw(rw) }
}
/// Creates a `UnixString` from a byte vector. /// /// See the module documentation for an example. /// pubfn from_vec(vec: Vec<u8>) -> Self {
FromInner::from_inner(Buf { inner: vec })
}
/// Yields the underlying byte vector of this `UnixString`. /// /// See the module documentation for an example. pubfn into_vec(self) -> Vec<u8> { self.into_inner().inner
}
}
#[cfg(feature = "alloc")] impl From<String> for UnixString { /// Converts a `String` into a [`UnixString`]. /// /// The conversion copies the data, and includes an allocation on the heap. /// /// [`UnixString`]: ../../std/ffi/struct.UnixString.html fn from(s: String) -> Self {
UnixString {
inner: Buf::from_string(s),
}
}
}
impl UnixStr { /// Coerces into an `UnixStr` slice. /// /// # Examples /// /// ``` /// use unix_str::UnixStr; /// /// let unix_str = UnixStr::new("foo"); /// ``` #[inline] pubfn new<S: AsRef<UnixStr> + ?Sized>(s: &S) -> &UnixStr {
s.as_ref()
}
#[inline] fn from_inner(inner: &Slice) -> &UnixStr { // Safety: UnixStr is just a wrapper of Slice, // therefore converting &Slice to &UnixStr is safe. unsafe { &*(inner as *const Slice as *const UnixStr) }
}
#[inline] #[cfg(feature = "alloc")] fn from_inner_mut(inner: &mut Slice) -> &mut UnixStr { // Safety: UnixStr is just a wrapper of Slice, // therefore converting &mut Slice to &mut UnixStr is safe. // Any method that mutates UnixStr must be careful not to // break platform-specific encoding, in particular Wtf8 on Windows. unsafe { &mut *(inner as *mut Slice as *mut UnixStr) }
}
/// Yields a `&str` slice if the `UnixStr` is valid Unicode. /// /// This conversion may entail doing a check for UTF-8 validity. /// /// # Examples /// /// ``` /// use unix_str::UnixStr; /// /// let unix_str = UnixStr::new("foo"); /// assert_eq!(unix_str.to_str(), Some("foo")); /// ``` pubfn to_str(&self) -> Option<&str> { self.inner.to_str()
}
/// Converts an `UnixStr` to a `Cow<str>`. /// /// Any non-Unicode sequences are replaced with /// `U+FFFD REPLACEMENT CHARACTER`. /// /// /// # Examples /// /// Calling `to_string_lossy` on an `UnixStr` with invalid unicode: /// /// ``` /// use unix_str::UnixStr; /// /// // Here, the values 0x66 and 0x6f correspond to 'f' and 'o' /// // respectively. The value 0x80 is a lone continuation byte, invalid /// // in a UTF-8 sequence. /// let source = [0x66, 0x6f, 0x80, 0x6f]; /// let unix_str = UnixStr::from_bytes(&source[..]); /// /// assert_eq!(unix_str.to_string_lossy(), "fo�o"); /// ``` #[cfg(feature = "alloc")] pubfn to_string_lossy(&self) -> Cow<'_, str> { self.inner.to_string_lossy()
}
/// Copies the slice into an owned [`UnixString`]. /// /// [`UnixString`]: struct.UnixString.html /// /// # Examples /// /// ``` /// use unix_str::{UnixStr, UnixString}; /// /// let unix_str = UnixStr::new("foo"); /// let unix_string = unix_str.to_unix_string(); /// assert_eq!(unix_string, UnixString::from("foo")); /// ``` #[cfg(feature = "alloc")] pubfn to_unix_string(&self) -> UnixString {
UnixString {
inner: self.inner.to_owned(),
}
}
/// Checks whether the `UnixStr` is empty. /// /// # Examples /// /// ``` /// use unix_str::UnixStr; /// /// let unix_str = UnixStr::new(""); /// assert!(unix_str.is_empty()); /// /// let unix_str = UnixStr::new("foo"); /// assert!(!unix_str.is_empty()); /// ``` #[inline] pubfn is_empty(&self) -> bool { self.inner.inner.is_empty()
}
/// Returns the length of this `UnixStr`. /// /// Note that this does **not** return the number of bytes in the string in /// OS string form. /// /// The length returned is that of the underlying storage used by `UnixStr`. /// As discussed in the [`UnixString`] introduction, [`UnixString`] and /// `UnixStr` store strings in a form best suited for cheap inter-conversion /// between native-platform and Rust string forms, which may differ /// significantly from both of them, including in storage size and encoding. /// /// This number is simply useful for passing to other methods, like /// [`UnixString::with_capacity`] to avoid reallocations. /// /// [`UnixString`]: struct.UnixString.html /// [`UnixString::with_capacity`]: struct.UnixString.html#method.with_capacity /// /// # Examples /// /// ``` /// use unix_str::UnixStr; /// /// let unix_str = UnixStr::new(""); /// assert_eq!(unix_str.len(), 0); /// /// let unix_str = UnixStr::new("foo"); /// assert_eq!(unix_str.len(), 3); /// ``` pubfn len(&self) -> usize { self.inner.inner.len()
}
/// Converts a `Box<UnixStr>` into an [`UnixString`] without copying /// allocating. /// /// [`UnixString`]: struct.UnixString.html #[cfg(feature = "alloc")] pubfn into_unix_string(self: Box<UnixStr>) -> UnixString { let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) };
UnixString {
inner: Buf::from_box(boxed),
}
}
/// Gets the underlying byte representation. /// /// Note: it is *crucial* that this API is private, to avoid /// revealing the internal, platform-specific encodings. #[inline] fn bytes(&self) -> &[u8] { unsafe { &*(&self.inner as *const _ as *const [u8]) }
}
/// Converts this string to its ASCII lower case equivalent in-place. /// /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', but non-ASCII letters /// are unchanged. /// /// To return a new lowercased value without modifying the existing one, use /// [`to_ascii_lowercase`]. /// /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// /// let mut s = UnixString::from("GRÜßE, JÜRGEN ❤"); /// /// s.make_ascii_lowercase(); /// /// assert_eq!("grÜße, jÜrgen ❤", s); /// ``` #[cfg(feature = "unixstring_ascii")] pubfn make_ascii_lowercase(&mutself) { self.inner.make_ascii_lowercase()
}
/// Converts this string to its ASCII upper case equivalent in-place. /// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. /// /// To return a new uppercased value without modifying the existing one, use /// [`to_ascii_uppercase`]. /// /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// /// let mut s = UnixString::from("Grüße, Jürgen ❤"); /// /// s.make_ascii_uppercase(); /// /// assert_eq!("GRüßE, JüRGEN ❤", s); /// ``` #[cfg(feature = "unixstring_ascii")] pubfn make_ascii_uppercase(&mutself) { self.inner.make_ascii_uppercase()
}
/// Returns a copy of this string where each character is mapped to its /// ASCII lower case equivalent. /// /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', /// but non-ASCII letters are unchanged. /// /// To lowercase the value in-place, use [`make_ascii_lowercase`]. /// /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// let s = UnixString::from("Grüße, Jürgen ❤"); /// /// assert_eq!("grüße, jürgen ❤", s.to_ascii_lowercase()); /// ``` #[cfg(all(feature = "alloc", feature = "unixstring_ascii"))] pubfn to_ascii_lowercase(&self) -> UnixString {
UnixString::from_inner(self.inner.to_ascii_lowercase())
}
/// Returns a copy of this string where each character is mapped to its /// ASCII upper case equivalent. /// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. /// /// To uppercase the value in-place, use [`make_ascii_uppercase`]. /// /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// let s = UnixString::from("Grüße, Jürgen ❤"); /// /// assert_eq!("GRüßE, JüRGEN ❤", s.to_ascii_uppercase()); /// ``` #[cfg(all(feature = "alloc", feature = "unixstring_ascii"))] pubfn to_ascii_uppercase(&self) -> UnixString {
UnixString::from_inner(self.inner.to_ascii_uppercase())
}
/// Checks if all characters in this string are within the ASCII range. /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// /// let ascii = UnixString::from("hello!\n"); /// let non_ascii = UnixString::from("Grüße, Jürgen ❤"); /// /// assert!(ascii.is_ascii()); /// assert!(!non_ascii.is_ascii()); /// ``` #[cfg(feature = "unixstring_ascii")] pubfn is_ascii(&self) -> bool { self.inner.is_ascii()
}
/// Checks that two strings are an ASCII case-insensitive match. /// /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, /// but without allocating and copying temporaries. /// /// # Examples /// /// ``` /// use unix_str::UnixString; /// /// assert!(UnixString::from("Ferris").eq_ignore_ascii_case("FERRIS")); /// assert!(UnixString::from("Ferrös").eq_ignore_ascii_case("FERRöS")); /// assert!(!UnixString::from("Ferrös").eq_ignore_ascii_case("FERRÖS")); /// ``` #[cfg(feature = "unixstring_ascii")] pubfn eq_ignore_ascii_case<S: ?Sized + AsRef<UnixStr>>(&self, other: &S) -> bool { self.inner.eq_ignore_ascii_case(&other.as_ref().inner)
}
/// Creates a `UnixStr` from a byte slice. /// /// See the module documentation for an example. pubfn from_bytes(slice: &[u8]) -> &Self { unsafe { mem::transmute(slice) }
}
/// Gets the underlying byte view of the `UnixStr` slice. /// /// See the module documentation for an example. pubfn as_bytes(&self) -> &[u8] {
&self.as_inner().inner
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.