diff --git a/Cargo.toml b/Cargo.toml index a3fd908..2f17f18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,14 +2,3 @@ name = "libshire" version = "0.1.0" edition = "2021" - -[features] -sqlx-actix-native-tls = ["sqlx/runtime-actix-native-tls"] -sqlx-async-std-native-tls = ["sqlx/runtime-async-std-native-tls"] -sqlx-actix-rustls = ["sqlx/runtime-actix-rustls"] -sqlx-async-std-rustls = ["sqlx/runtime-async-std-rustls"] -sqlx-tokio-rustls = ["sqlx/runtime-tokio-rustls"] -sqlx-tokio-native-tls = ["sqlx/runtime-tokio-native-tls"] - -[dependencies] -sqlx = { version = "0.5", optional = true } diff --git a/src/strings.rs b/src/strings.rs index a07aab1..959d589 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -8,17 +8,6 @@ use std::{ str::FromStr, }; -#[cfg(feature = "sqlx")] -use sqlx::{ - Database, - database::{HasArguments, HasValueRef}, - Decode, - Encode, - Type, - encode::IsNull, - error::BoxDynError, -}; - use buf::{StackString, HeapString}; /// A non-growable string where strings 22 bytes or shorter are stored on the stack and longer @@ -43,6 +32,12 @@ pub type ShString22 = ShString<22>; pub struct ShString(Repr); impl ShString { + #[inline] + #[must_use] + pub const fn empty() -> Self { + Self(Repr::Stack(StackString::empty())) + } + /// Creates a new `ShString` from the given string slice, putting it on the stack if possible /// or creating a new heap allocation otherwise. #[inline] @@ -160,6 +155,13 @@ impl ShString { } } +impl Default for ShString { + #[inline] + fn default() -> Self { + Self::empty() + } +} + impl ops::Deref for ShString { type Target = str; @@ -285,43 +287,6 @@ impl fmt::Display for ShString { } } -#[cfg(feature = "sqlx")] -impl<'r, DB, const N: usize> Decode<'r, DB> for ShString -where - DB: Database, - &'r str: Decode<'r, DB>, -{ - fn decode(value: >::ValueRef) -> Result { - <&'r str as Decode<'r, DB>>::decode(value).map(Self::new_from_str) - } -} - -#[cfg(feature = "sqlx")] -impl<'q, DB, const N: usize> Encode<'q, DB> for ShString -where - DB: Database, - for<'a> &'a str: Encode<'q, DB>, -{ - fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> IsNull { - <&str as Encode<'q, DB>>::encode(self.as_str(), buf) - } -} - -#[cfg(feature = "sqlx")] -impl Type for ShString -where - DB: Database, - for<'a> &'a str: Type, -{ - fn type_info() -> ::TypeInfo { - <&str as Type>::type_info() - } - - fn compatible(ty: &::TypeInfo) -> bool { - <&str as Type>::compatible(ty) - } -} - #[derive(Clone)] enum Repr { Stack(StackString), @@ -349,6 +314,24 @@ mod buf { } }; + /// Creates a new `StackString` from a given buffer and length. + /// + /// # Safety + /// + /// The first `len` bytes of `buf` (i.e. `buf[..len]`) must be valid UTF-8. + #[inline] + pub(super) const unsafe fn from_raw_parts(buf: [u8; N], len: u8) -> Self { + Self { buf, len } + } + + #[inline] + pub(super) const fn empty() -> Self { + // SAFETY: + // The first zero bytes of the buffer are valid UTF-8, because an empty byte slice is + // valid UTF-8. + unsafe { Self::from_raw_parts([0; N], 0) } + } + pub(super) fn from_str(s: &str) -> Option { let s = s.as_bytes(); @@ -361,7 +344,11 @@ mod buf { let mut buf = [0; N]; buf[..usize::from(len)].copy_from_slice(s); - Some(Self { buf, len }) + + // SAFETY: + // The first `len` bytes of the buffer are valid UTF-8 because the first `len` bytes of + // the buffer contain data copied from a `&str`, and `&str` is always valid UTF-8. + unsafe { Some(Self::from_raw_parts(buf, len)) } } pub(super) fn as_str(&self) -> &str {