Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions codec/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ serde = ["zalgo-codec-common/serde"]
# Derives the `Serialize`, `Deserialize`, and `Archive` traits from [`rkyv`](https://crates.io/crates/rkyv) for the `ZalgoString` struct.
rkyv = ["zalgo-codec-common/rkyv"]

# Derives the `Facet` trait from [`facet`](https://crates.io/crates/facet) for the `ZalgoString` struct.
facet = ["zalgo-codec-common/facet"]

# Enables the proc-macros `zalgo_embed!` and `zalgofy!`
macro = ["dep:zalgo-codec-macro"]

Expand Down
6 changes: 5 additions & 1 deletion common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ rust-version = "1.81.0"
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"], optional = true }
rkyv = { version = "0.8", default-features = false, features = ["alloc", "bytecheck"], optional = true }
bytecheck = { version = "0.8", default-features = false, optional = true }
facet = { version = "0.8", default-features = false, features = ["alloc"], optional = true }

[dev-dependencies]
criterion = { version = "0.5", default-features = false, features = ["html_reports"] }
Expand All @@ -33,9 +34,12 @@ serde = ["dep:serde"]
# Derives the `Serialize`, `Deserialize`, and `Archive` traits from [`rkyv`](https://crates.io/crates/rkyv) for the `ZalgoString` struct.
rkyv = ["dep:rkyv", "dep:bytecheck"]

# Derives the `Facet` trait from the [`facet`](https://crates.io/crates/facet) crate for the `ZalgoString` struct.
facet = ["dep:facet"]

# Enables the `Error` type to capture a `Backtrace`.
# Without this feature the crate is `no_std` compatible, but still uses the `alloc` crate.
std = ["serde?/std", "rkyv?/std", "bytecheck?/simdutf8"]
std = ["serde?/std", "rkyv?/std", "bytecheck?/simdutf8", "facet?/std"]

[[bench]]
name = "codec_bench"
Expand Down
2 changes: 2 additions & 0 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
//!
//! `rkyv`: derives the [`rkyv::Serialize`], [`rkyv::Deserialize`], and [`rkyv::Archive`] traits from [`rkyv`] for [`ZalgoString`].
//!
//! `facet`: derives the [`Facet`](facet::Facet) trait from [`facet`] for [`ZalgoString`].
//!
//! # Explanation
//!
//! Characters U+0300–U+036F are the combining characters for unicode Latin.
Expand Down
13 changes: 13 additions & 0 deletions common/src/zalgo_string/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ use alloc::{borrow::Cow, string::String, vec::Vec};
derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, CheckBytes)
)]
#[cfg_attr(feature = "rkyv", bytecheck(verify))]
#[cfg_attr(feature = "facet", derive(facet::Facet))]
#[cfg_attr(feature = "facet", facet(invariants = "zalgo_string_invariants"))]
pub struct ZalgoString(String);

#[cfg(feature = "rkyv")]
Expand Down Expand Up @@ -71,6 +73,17 @@ impl Default for ZalgoString {
}

impl ZalgoString {
#[cfg(feature = "facet")]
/// Checks the invariants of the `ZalgoString` type
/// for use with reflection with `facet`.
fn zalgo_string_invariants(&self) -> bool {
!self.0.is_empty()
&& core::str::from_utf8(self.0.as_bytes()).is_ok()
&& self.0.as_bytes()[0] == b'E'
&& self.0.len() % 2 == 1
&& crate::zalgo_decode(&self.0).is_ok()
}

/// Encodes the given string slice with [`zalgo_encode`] and stores the result in a new allocation.
///
/// # Errors
Expand Down