Crates.io | strck |
lib.rs | strck |
version | 1.0.0 |
source | src |
created_at | 2022-08-01 05:29:26.110146 |
updated_at | 2024-10-14 11:57:52.05137 |
description | Checked owned and borrowed strings |
homepage | |
repository | https://github.com/QnnOkabayashi/strck |
max_upload_size | |
id | 636540 |
size | 39,441 |
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.
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.
Check
can actually be backed by any 'static + AsRef<str>
type,
but String
is the default. ↩