PRECIS Framework: Preparation, Enforcement, and Comparison of Internationalized Strings in Application Protocols as described in rfc8264
This workspace implements the next crates:
This crate contains all the tools and parsers to generate PRECIS
tables from the Unicode Character Database UCD.
This crate is only used to generate code required by
precis-core and
precis-profiles crates.
It contains the main dependencies in order to download UCD files,
parse them and generate Rust code.
The core library of the PRECIS Framework. The base string classes IdentifierClass
and FreeFormClass are implemented here as defined in
rfc8264.
This crate provides the APIs required for profiles to be implemented.
You mostly won't require this crate unless you are implementing a new profile.
This crate implements the next PRECIS profiles:
- rfc8265. Preparation, Enforcement, and Comparison of Internationalized Strings Representing Usernames and Passwords.
- rfc8266. Preparation, Enforcement, and Comparison of Internationalized Strings Representing Nicknames
PRECIS profiles provides an API that allows application to prepare, enforce and compare internationalized strings.
// create OpaqueString profile
let profile = OpaqueString::new();
// prepare string
assert_eq!(profile.prepare("I'm Guybrush Threepwood, Mighty Pirate ☠"),
Ok(Cow::from("I'm Guybrush Threepwood, Mighty Pirate ☠")));
// enforce string
assert_eq!(profile.enforce("Look behind you, a three-headed monkey!🐒"),
Ok(Cow::from("Look behind you, a three-headed monkey!🐒")));
// compare strings
assert_eq!(profile.compare("That’s the second biggest 🐵 I’ve ever seen!",
"That’s the second biggest 🐵 I’ve ever seen!"), Ok(true));If you find yourself continuously creating and destroying profiles to perform
any of the operation described for internationalized strings. You can make use
of the PrecisFastInvocation trait.
Profiles implementing this trait will allow you to prepare, enforce or compare
internationalized strings without having to instantiate a specific profile.
Profiles usually use a static instance allocated with
LazyLock
assert_eq!(Nickname::prepare("Guybrush Threepwood"),
Ok(Cow::from("Guybrush Threepwood")));
assert_eq!(Nickname::enforce(" Guybrush Threepwood "),
Ok(Cow::from("Guybrush Threepwood")));
assert_eq!(Nickname::compare("Guybrush Threepwood ",
"guybrush threepwood"), Ok(true));- networking - Enables crates to download Unicode Character Database
UCDfiles from the network. This is helpful for developing and testing new Unicode releases, but this feature can not be enabled to generate the library documentation when the crate is uploaded tocrates.io. For security reasons, network access is not allowed to crates to avoid compromising the security of docs.rs itself.
PRECIS recommends using toLowerCase() operation as defined in the Unicode Standard
Unicode. This implementation uses the
one provided by Rust standard library
to_lowercase.
This operation performs an unconditional mapping without tailoring. That is, the
conversion is independent of context and language.
This project requires Rust 1.80 or later for stable LazyLock support.
The MSRV is:
- Explicitly declared in all
Cargo.tomlfiles viarust-version = "1.80" - Validated in CI to ensure compatibility
- Will only be increased in a new minor version release
The project has comprehensive test coverage with multiple testing approaches:
- Unit tests: tests covering core functionality
- Property-based tests: tests with proptest generating thousands of random inputs. See PROPTEST_GUIDE.md for details.
- Integration tests: RFC test vectors and edge cases
- Doc tests: tests in documentation examples
# Run all tests
cargo test
# Run property-based tests
cargo test proptest
# Run with increased cases
PROPTEST_CASES=10000 cargo test proptestSee PROPTEST_GUIDE.md and PROPTEST_CI.md for complete testing documentation.
The project supports fuzzing with cargo-fuzz to discover edge cases, panics, and bugs. Comprehensive fuzz targets available across core classes and all profiles:
# Install cargo-fuzz (requires nightly)
cargo install cargo-fuzz
# Run fuzzing (5 seconds quick test)
cd precis-profiles
cargo +nightly fuzz run nickname_enforce -- -max_total_time=5
# List available targets
cd precis-profiles && cargo +nightly fuzz list # Profile targets
cd precis-core && cargo +nightly fuzz list # Core class targetsProfile targets (prepare, enforce, compare for all profiles):
- Nickname:
nickname_enforce,nickname_prepare,nickname_compare,nickname_arbitrary - OpaqueString:
opaque_string_enforce,opaque_string_prepare,opaque_string_compare - UsernameCaseMapped:
username_casemapped,username_casemapped_prepare,username_casemapped_compare - UsernameCasePreserved:
username_casepreserved,username_casepreserved_prepare,username_casepreserved_compare
Core class targets (FreeformClass, IdentifierClass):
freeform_class_allows,freeform_class_get_value,freeform_class_codepointidentifier_class_allows,identifier_class_get_value,identifier_class_codepoint
CI Integration:
- ✅ ClusterFuzzLite runs automatically on every PR
- ✅ 5 minutes fuzzing per target
- ✅ Catches bugs before merge
- ✅ No setup required
See FUZZING.md for complete fuzzing guide.
The project uses Criterion.rs for performance benchmarking, integrated with CodSpeed for continuous performance tracking:
# Run all benchmarks
cargo bench
# Run specific benchmark
cargo bench --bench stringclass_bench
cargo bench --bench profiles_bench
# Compare with baseline
cargo bench -- --save-baseline main
# ... make changes ...
cargo bench -- --baseline mainCodSpeed Integration:
- ✅ Automatic performance tracking on every PR
- ✅ Regression detection
- ✅ Historical performance trends
See BENCHMARKING.md for complete benchmarking guide and CODSPEED.md for CodSpeed setup.
Patches and feedback are welcome.
If you find this project helpful, you may consider making a donation:
This project is licensed under either of