pub struct Text { /* private fields */ }Expand description
A SQLite text value.
One of the types in a SQLite database is a text type, internally these can have two opaque representations. UTF-8 and UTF-16 (of various endianesses). This library only interacts with the UTF-8 portion of the library.
Rust strings demand that all text is valid and well-formed UTF-8. SQLite despite calling what it returns as UTF-8 it doesn’t validate that the data it stores is well-formed. To put it in other terms, garbage in is garbage out. For a more detailed overview see the Invalid UTF Policy.
Since we want a thing wrapper on top of SQLite, that leaves us with having
to treat all text values as potentially malformed UTF-8, which is where this
wrapper type comes in. It provides some basic text-like functionality
similar to the [bstr crate] which makes your life a little easier. Such as
safely printing the value.
A type loaded as Text doesn’t validate that the underlying bytes are
valid or well-formed UTF-8, but provide some access to the literal
underlying data and convenience method for performing the text validation
locally such as Text::to_str.
For cases where you prefer to do this validation up front, we do provide
FromColumn implementations for string-like types where you can opt in to
eagerly perform the validation.
Reading the UTF policy carefully also leads you to the realization that all
SQLite APIs which might mix in user-provided text can produce malformed
UTF-8. Like Connection::error_message. Meaning even if we didn’t want to
support lossless text values, we would still want to treat these values
carefully.
§Examples
use sqll::{Code, Connection, Text};
let mut c = Connection::open_in_memory()?;
c.execute(r#"
CREATE TABLE example (data TEXT);
"#)?;
let mut insert = c.prepare("INSERT INTO example (data) VALUES (?)")?;
insert.execute(Text::new(b"invalid: \xF0\x90\x80\xF0\x90\x80"))?;
insert.execute(Text::new(b"valid: \xe2\x9d\xa4\xef\xb8\x8f"))?;
let mut stmt = c.prepare("SELECT data FROM example")?;
let e = stmt.next::<&str>().unwrap_err();
assert_eq!(e.code(), Code::MISMATCH);
stmt.reset()?;
let text = stmt.next::<&Text>()?.expect("expected value");
assert_eq!(text.as_bytes(), b"invalid: \xF0\x90\x80\xF0\x90\x80");
assert_eq!(text.to_string(), "invalid: ��");
let text = stmt.next::<&Text>()?.expect("expected value");
assert_eq!(text.as_bytes(), b"valid: \xe2\x9d\xa4\xef\xb8\x8f");
assert_eq!(text.to_str()?, "valid: ❤️");Implementations§
Source§impl Text
impl Text
Sourcepub fn new<T>(bytes: &T) -> &Self
pub fn new<T>(bytes: &T) -> &Self
Create a new Text from the given type coerced into a byte slice.
§Examples
use sqll::Text;
let a = Text::new(b"hello");
assert_eq!(a, "hello");Sourcepub const fn from_bytes(bytes: &[u8]) -> &Self
pub const fn from_bytes(bytes: &[u8]) -> &Self
Create a new Text from the given byte slice.
§Examples
use sqll::Text;
let t = Text::from_bytes(b"example");
assert_eq!(t, "example");Sourcepub fn as_bytes(&self) -> &[u8] ⓘ
pub fn as_bytes(&self) -> &[u8] ⓘ
Get the underlying byte slice for this Text.
§Examples
use sqll::Text;
let t = Text::new(b"example");
assert_eq!(t.as_bytes(), b"example");Sourcepub fn to_str(&self) -> Result<&str, Utf8Error>
pub fn to_str(&self) -> Result<&str, Utf8Error>
Attempt to convert this Text into a UTF-8 string slice.
Returns an error if the underlying bytes are not valid UTF-8.
§Examples
use sqll::Text;
let t = Text::new(b"example");
assert_eq!(t.to_str()?, "example");
let invalid = Text::new(b"\xF0\x90\x80");
assert!(invalid.to_str().is_err());Trait Implementations§
Source§impl AsRef<[u8]> for Text
Allow getting a reference to the underlying byte slice.
impl AsRef<[u8]> for Text
Allow getting a reference to the underlying byte slice.
§Examples
use sqll::Text;
let t = Text::new(b"example");
let b: &[u8] = t.as_ref();
assert_eq!(b, b"example");Source§impl<const N: usize> AsRef<Text> for FixedText<N>
Coerce into Text.
impl<const N: usize> AsRef<Text> for FixedText<N>
Coerce into Text.
§Examples
use sqll::{FixedText, Text};
let text = FixedText::from(*b"example");
let text: &Text = text.as_ref();
assert_eq!(text, "example");Source§impl AsRef<Text> for Text
Allow getting a reference to self.
impl AsRef<Text> for Text
Allow getting a reference to self.
§Examples
use sqll::Text;
let t = Text::new(b"example");
let t_ref: &Text = t.as_ref();
assert_eq!(t_ref, t);Source§impl AsRef<Text> for str
Allow getting a a string as a Text reference.
impl AsRef<Text> for str
Allow getting a a string as a Text reference.
§Examples
use sqll::Text;
let t = "example";
let t_ref: &Text = t.as_ref();
assert_eq!(t_ref, t);Source§impl Bind for Text
impl Bind for Text
§Examples
use sqll::{Connection, Text};
let c = Connection::open_in_memory()?;
c.execute(r#"
CREATE TABLE users (name TEXT, age INTEGER);
INSERT INTO users (name, age) VALUES ('Alice', 42), ('Bob', 30), ('', 25);
"#)?;
let mut stmt = c.prepare("SELECT age FROM users WHERE name = ?")?;
stmt.bind(Text::new(b"Alice"))?;
assert_eq!(stmt.iter::<i64>().collect::<Vec<_>>(), [Ok(42)]);
stmt.bind(Text::new(b""))?;
assert_eq!(stmt.iter::<i64>().collect::<Vec<_>>(), [Ok(25)]);
stmt.bind(b"")?;
assert_eq!(stmt.iter::<i64>().collect::<Vec<_>>(), []);Source§impl BindValue for Text
impl BindValue for Text
§Examples
use sqll::{Connection, Text, BIND_INDEX};
let c = Connection::open_in_memory()?;
c.execute(r#"
CREATE TABLE users (name TEXT, age INTEGER);
INSERT INTO users (name, age) VALUES ('Alice', 42), ('Bob', 30), ('', 25);
"#)?;
let mut stmt = c.prepare("SELECT age FROM users WHERE name = ?")?;
stmt.reset()?;
stmt.bind_value(BIND_INDEX, Text::new(b"Alice"))?;
assert_eq!(stmt.iter::<i64>().collect::<Vec<_>>(), [Ok(42)]);
stmt.reset()?;
stmt.bind_value(BIND_INDEX, Text::new(b""))?;
assert_eq!(stmt.iter::<i64>().collect::<Vec<_>>(), [Ok(25)]);
stmt.reset()?;
stmt.bind_value(BIND_INDEX, b"")?;
assert_eq!(stmt.iter::<i64>().collect::<Vec<_>>(), []);Source§impl Borrow<[u8]> for Text
Allow borrowing the underlying byte slice.
impl Borrow<[u8]> for Text
Allow borrowing the underlying byte slice.
§Examples
use sqll::Text;
use core::borrow::Borrow;
let t = Text::new(b"example");
let b: &[u8] = t.borrow();
assert_eq!(b, b"example");Source§impl Debug for Text
The debug implementation for Text will output a string literal style
representation of the text, escaping invalid UTF-8 bytes as \xNN escapes.
impl Debug for Text
The debug implementation for Text will output a string literal style
representation of the text, escaping invalid UTF-8 bytes as \xNN escapes.
§Examples
use sqll::Text;
assert_eq! {
format!("{:?}", Text::new(b"Hello, \xF0\x90\x80World!")),
"\"Hello, \\xF0\\x90\\x80World!\"",
};Source§impl Display for Text
The display implementation for Text will convert it into a UTF-8 string
lossily, replacing invalid sequences with the replacement character �.
impl Display for Text
The display implementation for Text will convert it into a UTF-8 string
lossily, replacing invalid sequences with the replacement character �.
§Examples
use sqll::Text;
let text = Text::new(b"before\xF0\x90\x80after");
assert_eq!(text.to_string(), "before�after");
let text = Text::new(b"before\xF0\x90\x80\xF0\x90\x80");
assert_eq!(text.to_string(), "before��");Source§impl<'stmt> FromColumn<'stmt> for &'stmt Text
FromColumn implementation which returns a borrowed Text.
impl<'stmt> FromColumn<'stmt> for &'stmt Text
FromColumn implementation which returns a borrowed Text.
§Examples
use sqll::{Connection, Text};
let c = Connection::open_in_memory()?;
c.execute(r#"
CREATE TABLE users (name TEXT);
INSERT INTO users (name) VALUES ('Alice'), ('Bob');
"#)?;
let mut stmt = c.prepare("SELECT name FROM users")?;
assert_eq!(stmt.next::<&Text>()?, Some(Text::new(b"Alice")));
assert_eq!(stmt.next::<&Text>()?, Some(Text::new(b"Bob")));
assert_eq!(stmt.next::<&Text>()?, None);Automatic conversion being denied:
use sqll::{Connection, Code, Text};
let c = Connection::open_in_memory()?;
c.execute(r#"
CREATE TABLE users (id INTEGER);
INSERT INTO users (id) VALUES (1), (2);
"#)?;
let mut stmt = c.prepare("SELECT id FROM users")?;
let e = stmt.next::<&Text>().unwrap_err();
assert_eq!(e.code(), Code::MISMATCH);Source§impl FromUnsizedColumn for Text
FromUnsizedColumn implementation for Text.
impl FromUnsizedColumn for Text
FromUnsizedColumn implementation for Text.
This corresponds exactly with the internal SQLite TEXT or
Text types.
§Examples
use sqll::{Connection, Text};
let c = Connection::open_in_memory()?;
c.execute(r#"
CREATE TABLE users (name TEXT);
INSERT INTO users (name) VALUES ('Alice'), ('Bob');
"#)?;
let mut stmt = c.prepare("SELECT name FROM users")?;
assert!(stmt.step()?.is_row());
let name = stmt.unsized_column::<Text>(0)?;
assert_eq!(name, "Alice");
assert!(stmt.step()?.is_row());
let name = stmt.unsized_column::<Text>(0)?;
assert_eq!(name, "Bob");Automatic conversion being denied:
use sqll::{Connection, Code};
let c = Connection::open_in_memory()?;
c.execute(r#"
CREATE TABLE users (id INTEGER);
INSERT INTO users (id) VALUES (1), (2);
"#)?;
let mut stmt = c.prepare("SELECT id FROM users")?;
let mut name = String::new();
while stmt.step()?.is_row() {
let e = stmt.unsized_column::<str>(0).unwrap_err();
assert_eq!(e.code(), Code::MISMATCH);
}Source§impl Hash for Text
Hash the text based on its byte sequence.
impl Hash for Text
Hash the text based on its byte sequence.
§Examples
use sqll::Text;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let t1 = Text::new(b"example");
let t2 = Text::new(b"example");
let mut hasher1 = DefaultHasher::new();
let mut hasher2 = DefaultHasher::new();
t1.hash(&mut hasher1);
t2.hash(&mut hasher2);
assert_eq!(hasher1.finish(), hasher2.finish());Inserting into a has set:
use sqll::Text;
use std::collections::HashSet;
let a = Text::new("Apple");
let b = Text::new("Banana");
let mut set = HashSet::from([a, b]);
let c = Text::new("Banana");
assert!(set.contains(&c));
assert!(!set.insert(c));Source§impl Ord for Text
Compare for ordering.
impl Ord for Text
Compare for ordering.
§Examples
use sqll::Text;
use std::collections::BTreeSet;
let a = Text::new("Apple");
let b = Text::new("Banana");
let mut set = BTreeSet::from([a, b]);
let c = Text::new("Banana");
assert!(set.contains(&c));
assert!(!set.insert(c));Source§impl<const N: usize> PartialEq<Text> for FixedText<N>
Compare the text for equality with a Text. This performs a byte-wise
comparison.
impl<const N: usize> PartialEq<Text> for FixedText<N>
Compare the text for equality with a Text. This performs a byte-wise
comparison.
§Examples
use sqll::{FixedText, Text};
let t1 = FixedText::from(*b"example");
let t2 = Text::new("example");
let t3 = Text::new("different");
assert_eq!(t1, *t2);
assert_ne!(t1, *t3);Source§impl PartialEq<str> for Text
Compare the text for equality with a str.
impl PartialEq<str> for Text
Compare the text for equality with a str.
This performs a byte-wise comparison.
§Examples
use sqll::Text;
let t = Text::new(b"example");
assert_eq!(t, "example");
assert_ne!(t, "different");Source§impl PartialEq for Text
Compare the text for equality with another Text. This performs a byte-wise
comparison.
impl PartialEq for Text
Compare the text for equality with another Text. This performs a byte-wise
comparison.
§Examples
use sqll::Text;
let t1 = Text::new(b"example");
let t2 = Text::new(b"example");
let t3 = Text::new(b"different");
assert_eq!(t1, t2);
assert_ne!(t1, t3);Source§impl PartialOrd for Text
Texts are ordered by their byte sequences.
impl PartialOrd for Text
Texts are ordered by their byte sequences.
§Examples
use sqll::Text;
let t1 = Text::new(b"apple");
let t2 = Text::new(b"banana");
assert!(t1 < t2);impl Eq for Text
Texts are equal if their bytes are equal.
§Examples
use sqll::Text;
let t1 = Text::new(b"example");
let t2 = Text::new(b"example");
assert!(t1 == t2);