strid/lib.rs
1//! Improve and strengthen your strings
2//!
3//! Strongly-typed APIs reduce errors and confusion over passing around un-typed strings.
4//! Braid helps in that endeavor by making it painless to create wrappers around your
5//! string values, ensuring that you use them in the right way every time.
6//!
7//! Examples of the documentation and implementations provided for braids are available
8//! below and in the [`strid_examples`] crate documentation.
9//!
10//! [`strid_examples`]: https://docs.rs/strid_examples/
11//!
12//! # Usage
13//!
14//! A braid is created by attaching `#[braid]` to a struct definition. The macro will take
15//! care of automatically updating the representation of the struct to wrap a string and
16//! generate the borrowed form of the strong type.
17//!
18//! ```
19//! use strid::braid;
20//!
21//! #[braid]
22//! pub struct DatabaseName;
23//! ```
24//!
25//! Braids of custom string types are also supported, so long as they implement a set of
26//! expected traits. If not specified, the type named `String` in the current namespace
27//! will be used. See the section on [custom string types] for more information.
28//!
29//! [custom string types]: #custom-string-types
30//!
31//! ```ignore
32//! use strid::braid;
33//! use compact_str::CompactString as String;
34//!
35//! #[braid]
36//! pub struct UserId;
37//! ```
38//!
39//! Once created, braids can be passed around as strongly-typed, immutable strings.
40//!
41//! ```
42//! # use strid::braid;
43//! #
44//! fn take_strong_string(n: DatabaseName) {}
45//! fn borrow_strong_string(n: &DatabaseNameRef) {}
46//!
47//! # #[braid]
48//! # pub struct DatabaseName;
49//! #
50//! let owned = DatabaseName::new(String::from("mongo"));
51//! borrow_strong_string(&owned);
52//! take_strong_string(owned);
53//! ```
54//!
55//! A braid can also be untyped for use in stringly-typed interfaces.
56//!
57//! ```
58//! # use strid::braid;
59//! #
60//! fn take_raw_string(s: String) {}
61//! fn borrow_raw_str(s: &str) {}
62//!
63//! # #[braid]
64//! # pub struct DatabaseName;
65//! #
66//! let owned = DatabaseName::new(String::from("mongo"));
67//! borrow_raw_str(owned.as_str());
68//! take_raw_string(owned.take());
69//! ```
70//!
71//! By default, the name of the borrowed form will be the same as the owned form
72//! with `Ref` appended to the end.
73//!
74//! ```
75//! # use strid::braid;
76//! #
77//! #[braid]
78//! pub struct DatabaseName;
79//!
80//! let owned = DatabaseName::from_static("mongo");
81//! let borrowed = DatabaseNameRef::from_static("mongo");
82//! # assert_eq!(owned, borrowed);
83//! ```
84//!
85//! If the name ends with `Buf`, however, then the borrowed form will drop the `Buf`, similar
86//! to the relationship between
87//! [`PathBuf`][std::path::PathBuf] and [`Path`][std::path::Path].
88//!
89//! [std::path::PathBuf]: https://doc.rust-lang.org/std/path/struct.PathBuf.html
90//! [std::path::Path]: https://doc.rust-lang.org/std/path/struct.Path.html
91//!
92//! ```
93//! # use strid::braid;
94//! #
95//! #[braid]
96//! pub struct DatabaseNameBuf;
97//!
98//! let owned = DatabaseNameBuf::from_static("mongo");
99//! let borrowed = DatabaseName::from_static("mongo");
100//! # assert_eq!(owned, borrowed);
101//! ```
102//!
103//! If the name ends with `String`, then the borrowed form will use `Str`.
104//!
105//! ```
106//! # use strid::braid;
107//! #
108//! #[braid]
109//! pub struct ConnectionString;
110//!
111//! let owned = ConnectionString::from_static("mysql://…");
112//! let borrowed = ConnectionStr::from_static("mysql://…");
113//! # assert_eq!(owned, borrowed);
114//! ```
115//!
116//! If a different name is desired, this behavior can be
117//! overridden by specifying the name of the reference type to create using the `ref`
118//! parameter.
119//!
120//! ```
121//! # use strid::braid;
122//! #
123//! #[braid(ref_name = "TempDb")]
124//! pub struct DatabaseNameBuf;
125//!
126//! let owned = DatabaseNameBuf::from_static("mongo");
127//! let borrowed = TempDb::from_static("mongo");
128//! let to_owned: DatabaseNameBuf = borrowed.to_owned();
129//! # assert_eq!(owned, borrowed);
130//! ```
131//!
132//! A default doc comment is added to the borrowed form that refers back to the owned form.
133//! If a custom doc comment is desired, the `ref_doc` parameter allows supplying custom
134//! documentation.
135//!
136//! ```
137//! # use strid::braid;
138//! #
139//! #[braid(ref_doc = "A temporary reference to a database name")]
140//! pub struct DatabaseName;
141//! #
142//! # let owned = DatabaseName::from_static("mongo");
143//! # let borrowed = DatabaseNameRef::from_static("mongo");
144//! # assert_eq!(owned, borrowed);
145//! ```
146//!
147//! Attributes added to the braid will be applied to both the owned and borrowed forms
148//! with the exception of `///` and `#[doc = ""]` attributes. To add an attribute to
149//! only the owned form, use the `owned_attr` parameter. Similarly, use `ref_attr` to
150//! add an attribute to only the borrowed form.
151//!
152//! ```
153//! use strid::braid;
154//!
155//! #[braid(
156//! owned_attr(must_use = "database name should always be used"),
157//! ref_attr(must_use = "created a reference, but never used it"),
158//! )]
159//! #[cfg(not(feature = "nightly"))]
160//! pub struct DatabaseName;
161//! ```
162//!
163//! # Extensibility
164//!
165//! The types created by the `braid` macro are placed in the same module where declared.
166//! This means additional functionality, including mutations, can be implemented easily.
167//!
168//! As a basic example, here is a type built to hold Amazon ARNs. The type has been
169//! extended to support some mutation and introspection.
170//!
171//! ```
172//! # use strid::braid;
173//! #
174//! #[braid]
175//! pub struct AmazonArnBuf;
176//!
177//! impl AmazonArnBuf {
178//! /// Append an ARN segment
179//! pub fn add_segment(&mut self, segment: &str) {
180//! self.0.push_str(":");
181//! self.0.push_str(segment);
182//! }
183//! }
184//!
185//! impl AmazonArn {
186//! /// Returns an iterator of all ARN segments
187//! pub fn get_segments(&self) -> std::str::Split<char> {
188//! self.0.split(':')
189//! }
190//!
191//! /// Returns the service segment of the ARN
192//! pub fn get_service(&self) -> &str {
193//! self.get_segments().nth(2).unwrap_or("")
194//! }
195//! }
196//! ```
197//!
198//! # Encapsulation
199//!
200//! Because code within the same module where the braid is defined are allowed to
201//! access the internal value, you can use a module in order to more strictly
202//! enforce encapsulation and limit accessibility that might otherwise violate
203//! established invariants. This may be particularly desired when the wrapped type
204//! requires [validation](#validation).
205//!
206//! ```
207//! mod amazon_arn {
208//! #[strid::braid]
209//! pub struct AmazonArnBuf;
210//!
211//! /* Additional impls that need access to the inner values */
212//! # impl AmazonArn {
213//! # pub fn get_segments(&self) -> std::str::Split<char> {
214//! # self.0.split(':')
215//! # }
216//! #
217//! # pub fn get_service(&self) -> &str {
218//! # self.get_segments().nth(2).unwrap_or("")
219//! # }
220//! # }
221//! }
222//!
223//! pub use amazon_arn::{AmazonArnBuf, AmazonArn};
224//!
225//! # fn main() {
226//! let x = AmazonArnBuf::from_static("arn:aws:iam::123456789012:user/Development");
227//! assert_eq!("iam", x.get_service());
228//! # }
229//! ```
230//!
231//! # Soundness
232//!
233//! This crate ensures that the `from_str` implementation provided for wrapping
234//! borrowed `str` slices does not extend lifetimes.
235//!
236//! In the example below, we verify that the borrowed `DatabaseNameRef` is unable
237//! to escape the lifetime of `data`. The following code snippet will fail to
238//! compile, because `data` will go out of scope and be dropped at the end of
239//! the block creating `ex_ref`.
240//!
241//! ```compile_fail
242//! # use strid::braid;
243//! #
244//! # #[braid]
245//! # pub struct DatabaseName;
246//! #
247//! let ex_ref = {
248//! let data = DatabaseName::new("test string");
249//! DatabaseNameRef::from_str(data.as_str())
250//! }; // `data` is dropped at this point
251//!
252//! // Which means that `ex_ref` would be invalid if allowed.
253//! println!("{}", ex_ref);
254//! ```
255//!
256//! # Validation
257//!
258//! Types can be configured to only contain certain values. This can be used to strongly
259//! enforce domain type boundaries, thus making invalid values unrepresentable.
260//!
261//! For example, if you wanted to have a username type that did not accept the `root` user,
262//! you have a few options:
263//!
264//! 1. Pass the username around as a string, validate that it isn't `root` at known entry points.
265//! 2. Create a username type and allow creation from a raw string, then validate it just after
266//! creation.
267//! 3. Create a strong username type that requires the value to be validated prior to being
268//! creatable.
269//!
270//! Braided strings give the strongest, third guarantee. The other two methods require constant
271//! vigilance to ensure that an unexpected `root` value doesn't sneak in through other backdoors.
272//!
273//! By default, Rust's module system allows items within the same module to have access to
274//! each other's non-public members. If not handled properly, this can lead to unintentionally
275//! violating invariants. Thus, for the strongest guarantees, it is recommended to use the module
276//! system to further control access to the interior values held by the braided type as
277//! described in the section on [encapsulation](#encapsulation).
278//!
279//! As a convenience, `from_static` functions are provided that accept `&'static str`. For fallible
280//! braids and the owned form of normalized braids, this function will panic if the value is not
281//! valid. For borrowed form of normalized braids, the function will panic if the value is not
282//! normalized.
283//!
284//! ```
285//! # use strid::braid;
286//! #
287//! #[derive(Debug, PartialEq, Eq)]
288//! pub struct InvalidUsername;
289//! // Error implementation elided
290//! # impl std::fmt::Display for InvalidUsername {
291//! # fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
292//! # f.write_str("invalid username")
293//! # }
294//! # }
295//! # strid::from_infallible!(InvalidUsername);
296//! # impl std::error::Error for InvalidUsername {}
297//!
298//! #[braid(validator)]
299//! pub struct NonRootUsername;
300//!
301//! impl strid::Validator for NonRootUsername {
302//! type Error = InvalidUsername;
303//! fn validate(s: &str) -> Result<(), Self::Error> {
304//! if s.is_empty() || s.eq_ignore_ascii_case("root") {
305//! Err(InvalidUsername)
306//! } else {
307//! Ok(())
308//! }
309//! }
310//! }
311//!
312//! assert!(NonRootUsername::new("".to_string()).is_err());
313//! assert!(NonRootUsername::new("root".to_string()).is_err());
314//! assert!(NonRootUsername::new("nobody".to_string()).is_ok());
315//!
316//! NonRootUsername::from_static("nobody");
317//!
318//! assert!(NonRootUsernameRef::from_str("").is_err());
319//! assert!(NonRootUsernameRef::from_str("root").is_err());
320//! assert!(NonRootUsernameRef::from_str("nobody").is_ok());
321//!
322//! NonRootUsernameRef::from_static("nobody");
323//! ```
324//!
325//! Foreign validators can also be used by specifying the name of the type that
326//! implements the validation logic.
327//!
328//! ```
329//! # use strid::braid;
330//! #
331//! # #[derive(Debug, PartialEq, Eq)]
332//! # pub struct InvalidUsername;
333//! # // Error implementation elided
334//! # impl std::fmt::Display for InvalidUsername {
335//! # fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
336//! # f.write_str("invalid username")
337//! # }
338//! # }
339//! # strid::from_infallible!(InvalidUsername);
340//! # impl std::error::Error for InvalidUsername {}
341//! #
342//! #[braid(validator = "UsernameValidator")]
343//! pub struct NonRootUsername;
344//!
345//! pub struct UsernameValidator;
346//!
347//! impl strid::Validator for UsernameValidator {
348//! /* … */
349//! # type Error = InvalidUsername;
350//! # fn validate(s: &str) -> Result<(), Self::Error> {
351//! # if s.is_empty() || s.eq_ignore_ascii_case("root") {
352//! # Err(InvalidUsername)
353//! # } else {
354//! # Ok(())
355//! # }
356//! # }
357//! }
358//!
359//! assert!(NonRootUsername::new("".to_string()).is_err());
360//! assert!(NonRootUsername::new("root".to_string()).is_err());
361//! assert!(NonRootUsername::new("nobody".to_string()).is_ok());
362//!
363//! NonRootUsername::from_static("nobody");
364//!
365//! assert!(NonRootUsernameRef::from_str("").is_err());
366//! assert!(NonRootUsernameRef::from_str("root").is_err());
367//! assert!(NonRootUsernameRef::from_str("nobody").is_ok());
368//!
369//! NonRootUsernameRef::from_static("nobody");
370//! ```
371//!
372//! Note: `Validator::Error` is expected to implement `From<Infallible>`. If
373//! you haven't implemented this trait, you'll receive an error of the
374//! following form:
375//!
376//! ```text
377//! the trait bound `MyError: std::convert::From<std::convert::Infallible>` is not satisfied
378//! the trait `std::convert::From<std::convert::Infallible>` is not implemented for `MyError`
379//! ```
380//!
381//! In order to assist in implementing this trait trivially, use the [`from_infallible!()`]
382//! helper macro:
383//!
384//! ```
385//! pub struct InvalidUsername;
386//!
387//! strid::from_infallible!(InvalidUsername);
388//! ```
389//!
390//! This expands to the following code:
391//!
392//! ```
393//! struct InvalidUsername;
394//! impl From<core::convert::Infallible> for InvalidUsername {
395//! #[inline(always)]
396//! fn from(x: core::convert::Infallible) -> Self {
397//! match x {}
398//! }
399//! }
400//! ```
401//!
402//! ## Normalization
403//!
404//! Braided strings can also have enforced normalization, which is carried out at the creation
405//! boundary. In this case, the `.from_str()` function on the borrowed form will return a
406//! [`Cow<Borrowed>`][alloc::borrow::Cow], which can be inspected to determine whether
407//! normalization and conversion to an owned value was required. In cases where the incoming
408//! value is expected to already be normalized, the `.from_normalized_str()` function can
409//! be used. This function will return an error if the value required normalization.
410//!
411//! Note that when implementing [`Validator`] for a braided type, the `validate` method
412//! must ensure that the value is already in normalized form and return an error if it is
413//! not.
414//!
415//! When using `serde` to deserialze directly to the borrowed form, care must be taken, as
416//! only already normalized values will be able to be deserialized. If normalization is
417//! expected, deserialize into the owned form or `Cow<Borrowed>`.
418//!
419//! Here is a toy example where the value must not be empty and must be composed of ASCII
420//! characters, but that is also normalized to use lowercase ASCII letters.
421//!
422//! ```
423//! # use strid::braid;
424//! use std::borrow::Cow;
425//!
426//! #[derive(Debug, PartialEq, Eq)]
427//! pub struct InvalidHeaderName;
428//! // Error implementation elided
429//! # impl std::fmt::Display for InvalidHeaderName {
430//! # fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
431//! # f.write_str("invalid header name")
432//! # }
433//! # }
434//! # strid::from_infallible!(InvalidHeaderName);
435//! # impl std::error::Error for InvalidHeaderName {}
436//!
437//! #[braid(normalizer)]
438//! pub struct HeaderName;
439//!
440//! impl strid::Validator for HeaderName {
441//! type Error = InvalidHeaderName;
442//! fn validate(s: &str) -> Result<(), Self::Error> {
443//! if s.is_empty() || !s.is_ascii() || s.as_bytes().iter().any(|&b| b'A' <= b && b <= b'Z') {
444//! Err(InvalidHeaderName)
445//! } else {
446//! Ok(())
447//! }
448//! }
449//! }
450//!
451//! impl strid::Normalizer for HeaderName {
452//! fn normalize(s: &str) -> Result<Cow<str>, Self::Error> {
453//! if s.is_empty() || !s.is_ascii() {
454//! Err(InvalidHeaderName)
455//! } else if s.as_bytes().iter().any(|&b| b'A' <= b && b <= b'Z') {
456//! Ok(Cow::Owned(s.to_ascii_lowercase()))
457//! } else {
458//! Ok(Cow::Borrowed(s))
459//! }
460//! }
461//! }
462//!
463//! assert!(HeaderName::new("".to_string()).is_err());
464//! assert_eq!("mixedcase", HeaderName::new("MixedCase".to_string()).unwrap().as_str());
465//! assert_eq!("lowercase", HeaderName::new("lowercase".to_string()).unwrap().as_str());
466//!
467//! assert_eq!("mixedcase", HeaderName::from_static("MixedCase").as_str());
468//! assert_eq!("lowercase", HeaderName::from_static("lowercase").as_str());
469//!
470//! assert!(HeaderNameRef::from_str("").is_err());
471//! assert_eq!("mixedcase", HeaderNameRef::from_str("MixedCase").unwrap().as_str());
472//! assert_eq!("lowercase", HeaderNameRef::from_str("lowercase").unwrap().as_str());
473//!
474//! assert!(HeaderNameRef::from_normalized_str("").is_err());
475//! assert!(HeaderNameRef::from_normalized_str("MixedCase").is_err());
476//! assert_eq!("lowercase", HeaderNameRef::from_normalized_str("lowercase").unwrap().as_str());
477//!
478//! assert_eq!("lowercase", HeaderNameRef::from_static("lowercase").as_str());
479//! ```
480//!
481//! ## Unchecked creation
482//!
483//! Where necessary for efficiency, it is possible to bypass the validations on creation through
484//! the use of the `.new_unchecked()` or `from_str_unchecked()` functions. These functions are
485//! marked as `unsafe`, as they require the caller to assert that they are fulfilling the
486//! implicit contract that the value be both valid and in normal form. If either of these
487//! constraints are violated, undefined behavior could result when downstream consumers depend
488//! on these constraints being upheld.
489//!
490//! ```compile_fail
491//! # use strid::braid;
492//! #
493//! # #[derive(Debug, PartialEq, Eq)]
494//! # pub struct InvalidUsername;
495//! # // Error implementation elided
496//! # impl std::fmt::Display for InvalidUsername {
497//! # fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
498//! # f.write_str("invalid username")
499//! # }
500//! # }
501//! # strid::from_infallible!(InvalidUsername);
502//! # impl std::error::Error for InvalidUsername {}
503//! #
504//! # #[braid(validator)]
505//! # pub struct NonRootUsername;
506//! #
507//! # impl strid::Validator for NonRootUsername {
508//! # type Error = InvalidUsername;
509//! # fn validate(s: &str) -> Result<(), Self::Error> {
510//! # if s.is_empty() || s.eq_ignore_ascii_case("root") {
511//! # Err(InvalidUsername)
512//! # } else {
513//! # Ok(())
514//! # }
515//! # }
516//! # }
517//! #
518//! NonRootUsername::new_unchecked("");
519//! NonRootUsernameRef::from_str_unchecked("nobody");
520//! ```
521//!
522//! If you find violations of your guarantees, you can look specifically for uses of `unsafe`.
523//!
524//! ```
525//! # use strid::braid;
526//! #
527//! # #[derive(Debug, PartialEq, Eq)]
528//! # pub struct InvalidUsername;
529//! # // Error implementation elided
530//! # impl std::fmt::Display for InvalidUsername {
531//! # fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
532//! # f.write_str("invalid username")
533//! # }
534//! # }
535//! # strid::from_infallible!(InvalidUsername);
536//! # impl std::error::Error for InvalidUsername {}
537//! #
538//! # #[braid(validator)]
539//! # pub struct NonRootUsername;
540//! #
541//! # impl strid::Validator for NonRootUsername {
542//! # type Error = InvalidUsername;
543//! # fn validate(s: &str) -> Result<(), Self::Error> {
544//! # if s.is_empty() || s.eq_ignore_ascii_case("root") {
545//! # Err(InvalidUsername)
546//! # } else {
547//! # Ok(())
548//! # }
549//! # }
550//! # }
551//! #
552//! unsafe {
553//! NonRootUsername::new_unchecked(String::from(""));
554//! NonRootUsernameRef::from_str_unchecked("root");
555//! }
556//! ```
557//!
558//! # Provided trait impls
559//!
560//! By default, the following traits will be automatically implemented.
561//!
562//! For the `Owned` type
563//! * [`core::clone::Clone`]
564//! * [`core::fmt::Debug`]
565//! * [`core::fmt::Display`]
566//! * [`core::hash::Hash`]
567//! * [`core::cmp::Eq`]
568//! * [`core::cmp::Ord`]
569//! * [`core::cmp::PartialEq<Owned>`]
570//! * [`core::cmp::PartialEq<Borrowed>`]
571//! * [`core::cmp::PartialEq<&Borrowed>`]
572//! * [`core::cmp::PartialEq<Box<Borrowed>>`]
573//! * [`core::cmp::PartialOrd`]
574//! * [`core::convert::AsRef<Borrowed>`]
575//! * [`core::convert::AsRef<str>`]
576//! * [`core::convert::From<&Borrowed>`]
577//! * [`core::convert::From<Box<Borrowed>>`]
578//! * [`core::convert::From<Cow<Borrowed>>`]
579//! * [`core::borrow::Borrow<Borrowed>`]
580//! * [`core::str::FromStr`]
581//! * [`core::ops::Deref`] where `Target = Borrowed`
582//!
583//! Additionally, unvalidated owned types implement
584//! * [`core::convert::From<String>`]
585//! * [`core::convert::From<&str>`]
586//!
587//! Validated and normalized owned types will instead implement
588//! * [`core::convert::TryFrom<String>`]
589//! * [`core::convert::TryFrom<&str>`]
590//!
591//! When normalized, the above conversions will normalize values.
592//!
593//! For the `Borrowed` type
594//! * [`core::fmt::Debug`]
595//! * [`core::fmt::Display`]
596//! * [`core::hash::Hash`]
597//! * [`core::cmp::Eq`]
598//! * [`core::cmp::Ord`]
599//! * [`core::cmp::PartialEq<Owned>`]
600//! * [`core::cmp::PartialEq<Borrowed>`]
601//! * [`core::cmp::PartialEq<&Borrowed>`]
602//! * [`core::cmp::PartialEq<Box<Borrowed>>`]
603//! * [`core::cmp::PartialOrd`]
604//! * [`core::convert::From<&Cow<Borrowed>>`]
605//! * [`alloc::borrow::ToOwned`] where `Owned = Owned`
606//!
607//! Additionally, unvalidated borrowed types implement
608//! * [`core::convert::From<&str>`]
609//!
610//! Validated and normalize borrowed types will instead implement
611//! * [`core::convert::TryFrom<&str>`]
612//!
613//! For `Cow<'static, Borrowed>`
614//! * [`core::convert::From<Owned>`]
615//!
616//! For `Cow<Borrowed>`
617//! * [`core::convert::From<&Borrowed>`]
618//!
619//! For `Box<Borrowed>`
620//! * [`core::convert::From<Owned>`]
621//!
622//! The above conversion will fail if the value is not already normalized.
623//!
624//! Types that are not normalized will additionally implement
625//! * [`core::borrow::Borrow<str>`]
626//!
627//! `Borrow<str>` cannot be implemented for normalized braids because equality and hashing
628//! of equivalent braid values will have differing results for equality, which violates the
629//! contract implied by the `Borrow` trait.
630//!
631//! `Deref` to a `str` is explicitly not implemented. This means that an explicit call is
632//! required to treat a value as an untyped string, whether `.as_str()`, `.to_string()`, or
633//! `.into_string()`
634//!
635//! ## Omitting `Clone`
636//!
637//! For some types, it may be desirable to prevent arbitrary cloning of a type. In that case,
638//! the `clone` parameter can be used to prevent automatically deriving
639//! [`Clone`][core::clone::Clone].
640//!
641//! ```
642//! # use strid::braid;
643//! # use static_assertions::assert_not_impl_any;
644//! #
645//! #[braid(clone = "omit")]
646//! pub struct Sensitive;
647//!
648//! assert_not_impl_any!(Sensitive: Clone);
649//! ```
650//!
651//! ## Custom `Display`, `Debug`, and `PartialOrd`/`Ord` implementations
652//!
653//! By default, the implementations of [`Display`][core::fmt::Display], [`Debug`][core::fmt::Debug]
654//! [`PartialOrd`][core::cmp::PartialOrd], and [`Ord`][core::cmp::Ord]
655//! provided by a braid delegate directly to the underlying [`String`][alloc::string::String]
656//! or [`str`] types. If a custom implementation is desired, the automatic derivation of these
657//! traits can be controlled by the `display`, `debug`, and `ord` parameters. Both of these
658//! parameters accept one of `impl`, `owned`, or `omit`. By default, the `impl` derivation
659//! mode is used.
660//!
661//! The modes have the following effects:
662//!
663//! * `impl`: Format the owned and reference type transparently as the underlying string (slice)
664//! type.
665//! * `owned`: Automatically provide an owned implementation that transparently delegates to the
666//! implementation of the borrowed form. The consumer must provide their custom implementation on
667//! the borrowed form.
668//! * `omit`: No implementations are provided for the owned or borrowed forms. These must be
669//! implemented by the consumer if they are desired.
670//!
671//! Note: Omitting a `PartialOrd` and `Ord` implementation will make the braid unable to be
672//! used as a key in a `BTreeMap` or `BTreeSet`.
673//!
674//! As an example:
675//!
676//! ```
677//! # use strid::braid;
678//! use std::fmt;
679//! #
680//! #[braid(clone = "omit", display = "owned", debug = "owned")]
681//! pub struct Sensitive;
682//!
683//! impl fmt::Debug for SensitiveRef {
684//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
685//! f.write_str("SENSITIVE")
686//! }
687//! }
688//!
689//! impl fmt::Display for SensitiveRef {
690//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
691//! f.write_str("SENSITIVE DISPLAY")
692//! }
693//! }
694//!
695//! let owned = Sensitive::from_static("secret value");
696//! assert_eq!("SENSITIVE", format!("{:?}", owned));
697//! assert_eq!("SENSITIVE DISPLAY", format!("{}", owned));
698//! assert_eq!("secret value", owned.as_str());
699//!
700//! let borrowed: &SensitiveRef = &owned;
701//! assert_eq!("SENSITIVE", format!("{:?}", borrowed));
702//! assert_eq!("SENSITIVE DISPLAY", format!("{}", borrowed));
703//! assert_eq!("secret value", borrowed.as_str());
704//! ```
705//!
706//! # Serde
707//!
708//! [`Serialize`] and [`Deserialize`] implementations from the [`serde`] crate
709//! can be automatically generated by including `serde` in the argument list for the macro.
710//!
711//! [`serde`]: https://docs.rs/serde/*/serde/
712//! [`Serialize`]: https://docs.rs/serde/*/serde/trait.Serialize.html
713//! [`Deserialize`]: https://docs.rs/serde/*/serde/trait.Deserialize.html
714//!
715//! ```
716//! # use strid::braid;
717//! #
718//! #[braid(serde)]
719//! pub struct Username;
720//!
721//! let username = Username::from_static("root");
722//! let json = serde_json::to_string(&username).unwrap();
723//! let new_username: Username = serde_json::from_str(&json).unwrap();
724//! # assert_eq!(username, new_username);
725//! ```
726//!
727//! Such automatic implementations will also properly handle string values that require
728//! validation. This automatic validation has the benefit of easing use with _Serde_ while
729//! still protecting the integrity of the type.
730//!
731//! ```
732//! # use strid::braid;
733//! #
734//! #[derive(Debug, PartialEq, Eq)]
735//! pub struct InvalidUsername;
736//! // Error implementation elided
737//! # impl std::fmt::Display for InvalidUsername {
738//! # fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
739//! # f.write_str("invalid username")
740//! # }
741//! # }
742//! # strid::from_infallible!(InvalidUsername);
743//! # impl std::error::Error for InvalidUsername {}
744//!
745//! #[braid(serde, validator)]
746//! pub struct Username;
747//!
748//! impl strid::Validator for Username {
749//! type Error = InvalidUsername;
750//! fn validate(s: &str) -> Result<(), Self::Error> {
751//! if s.is_empty() || s.eq_ignore_ascii_case("root") {
752//! Err(InvalidUsername)
753//! } else {
754//! Ok(())
755//! }
756//! }
757//! }
758//!
759//! assert!(serde_json::from_str::<Username>("\"\"").is_err());
760//! assert!(serde_json::from_str::<Username>("\"root\"").is_err());
761//! assert!(serde_json::from_str::<Username>("\"nobody\"").is_ok());
762//!
763//! assert!(serde_json::from_str::<&UsernameRef>("\"\"").is_err());
764//! assert!(serde_json::from_str::<&UsernameRef>("\"root\"").is_err());
765//! assert!(serde_json::from_str::<&UsernameRef>("\"nobody\"").is_ok());
766//! ```
767//!
768//! # Custom string types
769//!
770//! The `braid` macro can be used to define a custom string type that wraps types
771//! other than the standard `String`. This allows defining a braid that is backed
772//! by a type that offers small-string optimizations, such as [`SmartString`] or
773//! [`CompactString`].
774//!
775//! Functions that expose the inner wrapped type can be made private by adding the
776//! `no_expose` parameter to avoid leaking the type in the public interface.
777//!
778//! [`SmartString`]: https://docs.rs/smartstring/*/smartstring/struct.SmartString.html
779//! [`CompactString`]: https://docs.rs/compact_str/*/compact_str/struct.CompactString.html
780//!
781//! ```ignore
782//! # use strid::braid;
783//! use compact_str::CompactString;
784//! use smartstring::{SmartString, LazyCompact};
785//!
786//! #[braid(no_expose)]
787//! pub struct UserId(CompactString);
788//!
789//! #[braid(no_expose)]
790//! pub struct AltUserId(SmartString<LazyCompact>);
791//! ```
792//!
793//! It can also be used to wrap a [`ByteString`], which is a string backed by
794//! [`Bytes`], which may be useful if the type is primarily used in contexts
795//! where a zero-copy implementation is preferred.
796//!
797//! [`ByteString`]: https://docs.rs/bytestring/*/bytestring/struct.ByteString.html
798//! [`Bytes`]: https://docs.rs/bytes/*/bytes/struct.Bytes.html
799//!
800//! ```ignore
801//! # use strid::braid;
802//! use bytestring::ByteString;
803//!
804//! #[braid]
805//! pub struct ZeroCopyIdentifier(ByteString);
806//! ```
807//!
808//! ## Requirements
809//!
810//! In order to be used as a custom string type, the type must implement the
811//! following traits:
812//!
813//! * [`core::clone::Clone`] (unless `clone` is `omit`)
814//! * [`core::fmt::Debug`] (unless `debug` is `omit`)
815//! * [`core::fmt::Display`] (unless `display` is `omit`)
816//! * [`core::cmp::Eq`]
817//! * [`core::cmp::PartialEq`]
818//! * [`core::hash::Hash`]
819//! * [`core::cmp::Ord`] (unless `ord` is `omit`)
820//! * [`core::cmp::PartialOrd`] (unless `ord` is `omit`)
821//! * [`serde::Serialize`] (unless `serde` is `omit`)
822//! * [`serde::Deserialize`] (unless `serde` is `omit`)
823//! * [`core::convert::From<&str>`]
824//! * [`core::convert::From<Box<str>>`]
825//! * [`core::convert::AsRef<str>`]
826//! * [`core::convert::Into<String>`]
827//!
828//! [`serde::Serialize`]: https://docs.rs/serde/*/serde/trait.Serialize.html
829//! [`serde::Deserialize`]: https://docs.rs/serde/*/serde/trait.Deserialize.html
830//!
831//! # `no_std` support
832//!
833//! Braids can be implemented in `no_std` environments with `alloc`. By adding the
834//! `no_std` parameter to the macro, all impls will reference the `core` or `alloc`
835//! crates instead of the `std` crate, as appropriate.
836//!
837//! ```
838//! extern crate alloc;
839//!
840//! use strid::braid;
841//! use alloc::string::String;
842//!
843//! #[braid(no_std)]
844//! pub struct NoStdLibWrapper;
845//! #
846//! # fn main() {}
847//! ```
848//!
849//! In environments without an allocator, `braid_ref` can be used to create a
850//! reference-only braid. In order to remove the `alloc` dependency in `strid`,
851//! specify `default-features = "false"` in the `Cargo.toml` file.
852//!
853//! ```
854//! use strid::braid_ref;
855//!
856//! #[braid_ref(no_std)]
857//! pub struct NoStdValue;
858//! #
859//! # fn main() {}
860//! ```
861//!
862//! # Safety
863//!
864//! Braid uses limited `unsafe` in order to be able to reinterpret string slices
865//! (`&str`) as the borrowed form. Because this functionality is provided as a
866//! macro, using the `#![forbid(unsafe_code)]` lint level on a crate that generates
867//! braids will result in compiler errors. Instead, the crate can be annotated with
868//! `#![deny(unsafe_code)]`, which allows for overrides as appropriate. The functions
869//! that require `unsafe` to work correctly are annotated with `#[allow(unsafe_code)]`,
870//! and all usages of unsafe that the macro generates are annotated with `SAFETY`
871//! code comments.
872//!
873//! If strict adherence to forbid unsafe code is required, then the types can be
874//! segregated into an accessory crate without the prohibition, and then consumed
875//! safely from crates that otherwise forbid unsafe code.
876
877#![warn(
878 missing_docs,
879 unused_import_braces,
880 unused_imports,
881 unused_qualifications
882)]
883#![deny(
884 missing_debug_implementations,
885 trivial_casts,
886 trivial_numeric_casts,
887 unused_must_use
888)]
889#![deny(unsafe_code)]
890#![no_std]
891
892#[cfg(feature = "alloc")]
893extern crate alloc;
894
895/// A validator that can verify a given input is valid given certain preconditions
896///
897/// If the type can be normalized, this implementation should also validate that
898/// the value is _already in normalized form_.
899pub trait Validator {
900 /// The error produced when the string is invalid
901 ///
902 /// `TryFrom<String>::Error` for the wrapped type must be convertable into this
903 /// error type. In most cases, this conversion is infallible, and so the error
904 /// type needs to implement `From<Infallible>`. See the [`from_infallible!()`]
905 /// helper macro to quickly implement this for your error type.
906 type Error;
907
908 /// Validates a string according to a predetermined set of rules
909 ///
910 /// # Errors
911 ///
912 /// Returns an error if the string is invalid or not in normalized form.
913 fn validate(raw: &str) -> Result<(), Self::Error>;
914}
915
916/// A normalizer that can verify a given input is valid
917/// and performs necessary normalization
918#[cfg(feature = "alloc")]
919pub trait Normalizer: Validator {
920 /// Validates and normalizes the borrowed input
921 ///
922 /// # Errors
923 ///
924 /// Returns an error if the string is invalid and cannot be normalized.
925 fn normalize(raw: &str) -> Result<::alloc::borrow::Cow<'_, str>, Self::Error>;
926}
927
928/// Utility macro for easily defining `From<Infallible>` for a given type.
929///
930/// # Example
931///
932/// ```
933/// use core::convert::Infallible;
934/// use strid::from_infallible;
935///
936/// pub struct MyType;
937///
938/// from_infallible!(MyType);
939///
940/// let result: Result<(), Infallible> = Ok(());
941/// let my_result: Result<(), MyType> = result.map_err(MyType::from);
942/// ```
943#[macro_export]
944macro_rules! from_infallible {
945 ($ty:ty) => {
946 impl ::core::convert::From<::core::convert::Infallible> for $ty {
947 // This should always be trivially inlineable as it allows
948 // the compiler to eliminate code paths from this unreachable path.
949 #[inline(always)]
950 fn from(x: ::core::convert::Infallible) -> Self {
951 match x {}
952 }
953 }
954 };
955}
956
957pub use facet;
958pub use strid_macros::{braid, braid_ref};