mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
Better docs and cleaner SmallCString
This commit is contained in:
parent
ac30e169ae
commit
abbab7216a
@ -1,8 +1,11 @@
|
|||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::ffi::{CStr, CString, NulError};
|
use std::ffi::{CStr, CString, NulError};
|
||||||
|
|
||||||
|
/// Similar to std::ffi::CString, but avoids heap allocating if the string is
|
||||||
|
/// small enough. Also guarantees it's input is UTF-8 -- used for cases where we
|
||||||
|
/// need to pass a NUL-terminated string to SQLite, and we have a `&str`.
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct SmallCString(smallvec::SmallVec<[u8; 16]>);
|
pub(crate) struct SmallCString(smallvec::SmallVec<[u8; 16]>);
|
||||||
|
|
||||||
impl SmallCString {
|
impl SmallCString {
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -13,21 +16,50 @@ impl SmallCString {
|
|||||||
let mut buf = SmallVec::with_capacity(s.len() + 1);
|
let mut buf = SmallVec::with_capacity(s.len() + 1);
|
||||||
buf.extend_from_slice(s.as_bytes());
|
buf.extend_from_slice(s.as_bytes());
|
||||||
buf.push(0);
|
buf.push(0);
|
||||||
Ok(Self(buf))
|
let res = Self(buf);
|
||||||
|
res.debug_checks();
|
||||||
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_str(&self) -> &str {
|
pub fn as_str(&self) -> &str {
|
||||||
debug_assert!(std::str::from_utf8(&self.as_bytes_without_nul()).is_ok());
|
self.debug_checks();
|
||||||
// Constructor takes a &str so this is safe.
|
// Constructor takes a &str so this is safe.
|
||||||
unsafe { std::str::from_utf8_unchecked(&self.as_bytes_without_nul()) }
|
unsafe { std::str::from_utf8_unchecked(self.as_bytes_without_nul()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the bytes not including the NUL terminator. E.g. the bytes which
|
||||||
|
/// make up our `str`:
|
||||||
|
/// - `SmallCString::new("foo").as_bytes_without_nul() == b"foo"`
|
||||||
|
/// - `SmallCString::new("foo").as_bytes_with_nul() == b"foo\0"
|
||||||
|
#[inline]
|
||||||
|
pub fn as_bytes_without_nul(&self) -> &[u8] {
|
||||||
|
self.debug_checks();
|
||||||
|
&self.0[..self.len()]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the bytes behind this str *including* the NUL terminator. This
|
||||||
|
/// should never return an empty slice.
|
||||||
|
#[inline]
|
||||||
|
pub fn as_bytes_with_nul(&self) -> &[u8] {
|
||||||
|
self.debug_checks();
|
||||||
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_bytes_without_nul(&self) -> &[u8] {
|
#[cfg(debug_assertions)]
|
||||||
&self.0[..self.0.len() - 1]
|
fn debug_checks(&self) {
|
||||||
|
debug_assert_ne!(self.0.len(), 0);
|
||||||
|
debug_assert_eq!(self.0[self.0.len() - 1], 0);
|
||||||
|
let strbytes = &self.0[..(self.0.len() - 1)];
|
||||||
|
debug_assert!(!strbytes.contains(&0));
|
||||||
|
debug_assert!(std::str::from_utf8(strbytes).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
fn debug_checks(&self) {}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
debug_assert_ne!(self.0.len(), 0);
|
debug_assert_ne!(self.0.len(), 0);
|
||||||
@ -35,14 +67,16 @@ impl SmallCString {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(unused)] // clippy wants this function.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.len() == 0
|
self.len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_cstr(&self) -> &CStr {
|
pub fn as_cstr(&self) -> &CStr {
|
||||||
debug_assert!(CStr::from_bytes_with_nul(&self.0).is_ok());
|
let bytes = self.as_bytes_with_nul();
|
||||||
unsafe { CStr::from_bytes_with_nul_unchecked(&self.0) }
|
debug_assert!(CStr::from_bytes_with_nul(bytes).is_ok());
|
||||||
|
unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cold]
|
#[cold]
|
||||||
@ -103,7 +137,10 @@ mod test {
|
|||||||
// things work.
|
// things work.
|
||||||
assert_eq!(SmallCString::default().0, SmallCString::new("").unwrap().0);
|
assert_eq!(SmallCString::default().0, SmallCString::new("").unwrap().0);
|
||||||
assert_eq!(SmallCString::new("foo").unwrap().len(), 3);
|
assert_eq!(SmallCString::new("foo").unwrap().len(), 3);
|
||||||
assert_eq!(SmallCString::new("foo").unwrap().0.as_slice(), b"foo\0");
|
assert_eq!(
|
||||||
|
SmallCString::new("foo").unwrap().as_bytes_with_nul(),
|
||||||
|
b"foo\0"
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
SmallCString::new("foo").unwrap().as_bytes_without_nul(),
|
SmallCString::new("foo").unwrap().as_bytes_without_nul(),
|
||||||
b"foo",
|
b"foo",
|
||||||
|
Loading…
Reference in New Issue
Block a user