9fc41dc37c
Depends on D167675 Differential Revision: https://phabricator.services.mozilla.com/D167674 |
||
---|---|---|
.. | ||
src | ||
.cargo-checksum.json | ||
Cargo.toml | ||
LICENSE | ||
README.md |
README.md
Checked owned and borrowed strings.
Overview
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. Implementing
the Invariant
trait is left to other crates, such as strck_ident
.
"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.
Motivation
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.
Use cases
Checked strings without allocating
The main benefit strck
offers is validating borrowed strings via the
Ck
type without having to allocate in the result.
use strck_ident::{Ck, IntoCk, rust::RustIdent};
let this_ident: &Ck<RustIdent> = "this".ck().unwrap();
Checked zero-copy deserialization
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_ident::{Ck, 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_ident
provides Ident
as an
alias for Ck<UnicodeIdent>
, which should be used in practice.
Infallible parsing
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.
Postfix construction with 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_ident::{IntoCheck, IntoCk, unicode::UnicodeIdent};
let this_ident = "this".ck::<UnicodeIdent>().unwrap();
let this_foo_ident = format!("{}_foo", this_ident).check::<UnicodeIdent>().unwrap();
Documentation
See the crate-level documentation for more details.
-
Check
can actually be backed by any'static + AsRef<str>
type, butString
is the default. ↩︎