Checked owned and borrowed strings.
The Rust standard library provides the String
and str
types, which wrap Vec<u8>
and [u8]
respectively, with the invariant that the contents are valid UTF-8.
This crate abstracts the idea of type-level invariants on strings by introducing the immutable Check
and Ck
types, where the invariants are determined by a generic Invariant
type parameter. It offers UnicodeIdent
and RustIdent
Invariant
s, which are enabled by the ident
feature flag.
“strck” comes from “str check”, similar to how rustc has typeck and borrowck for type check and borrow check respectively.
See the documentation for more details.
Libraries working with string-like types with certain properties, like identifiers, quickly become confusing as &str
and String
begin to pollute type signatures everywhere. One solution is to manually implement an owned checked string type like syn::Ident
to disambiguate the type signatures and validate the string. The downside is that new values cannot be created without allocation, which is unnecessary when only a borrowed version is required.
strck
solves this issue by providing a checked borrowed string type, Ck
, alongside a checked owned string type, Check
. These serve as thin wrappers around str
and String
[^1] respectively, and prove at the type level that the contents satisfy the Invariant
that the wrapper is generic over.
[^1]: Check
can actually be backed by any 'static + AsRef<str>
type, but String
is the default.
The main benefit strck
offers is validating borrowed strings via the Ck
type without having to allocate in the result.
use strck::{Ck, IntoCk, ident::rust::RustIdent}; let this_ident: &Ck<RustIdent> = "this".ck().unwrap();
When the serde
feature flag is enabled, Ck
s can be used to perform checked zero-copy deserialization, which requires the #[serde(borrow)]
attribute.
use strck::{Ck, ident::unicode::UnicodeIdent}; #[derive(Serialize, Deserialize)] struct Player<'a> { #[serde(borrow)] username: &'a Ck<UnicodeIdent>, level: u32, }
Note that this code sample explicitly uses Ck<UnicodeIdent>
to demonstrate that the type is a Ck
. However, strck
provides Ident
as an alias for Ck<UnicodeIdent>
, which should be used in practice.
For types where string validation is relatively cheap but parsing is costly and fallible, strck
can be used with a custom Invariant
as an input to make an infallible parsing function.
IntoCk
and IntoCheck
This crate exposes two helper traits, IntoCk
and IntoCheck
. When in scope, the .ck()
and .check()
functions can be used to create Ck
s and Check
s respectively:
use strck::{IntoCheck, IntoCk, ident::unicode::UnicodeIdent}; let this_ident = "this".ck::<UnicodeIdent>().unwrap(); let this_foo_ident = format!("{}_foo", this_ident).check::<UnicodeIdent>().unwrap();
See the crate-level documentation for more details.