pct_str/lib.rs
1//! This crate provides two types, [`PctStr`] and [`PctString`], similar to `str` and [`String`],
2//! representing percent-encoded strings used in URL, URI, IRI, etc.
3//! You can use them to encode, decode and compare percent-encoded strings.
4//!
5//! # Basic usage
6//!
7//! You can parse/decode percent-encoded strings by building a [`PctStr`] slice over a `str` slice.
8//!
9//! ```
10//! use pct_str::PctStr;
11//!
12//! let pct_str = PctStr::new("Hello%20World%21").unwrap();
13//! assert_eq!(pct_str, "Hello World!");
14//!
15//! let decoded_string: String = pct_str.decode();
16//! assert_eq!(decoded_string, "Hello World!")
17//! ```
18//!
19//! To create new percent-encoded strings, use the [`PctString`] to copy or encode new strings.
20//!
21//! ```
22//! use pct_str::{PctString, UriReserved};
23//!
24//! // Copy the given percent-encoded string.
25//! let pct_string = PctString::new("Hello%20World%21").unwrap();
26//!
27//! // Encode the given regular string.
28//! let pct_string = PctString::encode("Hello World!".chars(), UriReserved::Any);
29//!
30//! assert_eq!(pct_string.as_str(), "Hello%20World%21");
31//! ```
32//!
33//! You can choose which character will be percent-encoded by the `encode` function
34//! by implementing the [`Encoder`] trait.
35//!
36//! ```
37//! use pct_str::{UriReserved, PctString};
38//!
39//! struct CustomEncoder;
40//!
41//! impl pct_str::Encoder for CustomEncoder {
42//! fn encode(&self, c: char) -> bool {
43//! UriReserved::Any.encode(c) || c.is_uppercase()
44//! }
45//! }
46//!
47//! let pct_string = PctString::encode("Hello World!".chars(), CustomEncoder);
48//! assert_eq!(pct_string.as_str(), "%48ello%20%57orld%21")
49//! ```
50//!
51//! [`String`]: std::string::String
52//! [`PctStr`]: crate::nsized::PctStr
53//! [`PctString`]: crate::sized::PctString
54//! [`Encoder`]: crate::encoder::Encoder
55#![cfg_attr(not(feature = "std"), no_std)]
56
57mod encoder;
58mod error;
59mod nsized;
60#[cfg(feature = "std")]
61mod sized;
62pub(crate) mod util;
63
64pub use encoder::*;
65pub use error::*;
66pub use nsized::*;
67#[cfg(feature = "std")]
68pub use sized::*;
69
70#[cfg(test)]
71mod tests {
72 use std::convert::TryInto;
73
74 use super::*;
75
76 #[test]
77 fn pct_encoding_invalid() {
78 let s = "%FF%FE%20%4F";
79 assert!(PctStr::new(s).is_err());
80 let s = "%36%A";
81 assert!(PctStr::new(s).is_err());
82 let s = "%%32";
83 assert!(PctStr::new(s).is_err());
84 let s = "%%32";
85 assert!(PctStr::new(s).is_err());
86 }
87
88 #[test]
89 fn pct_encoding_valid() {
90 let s = "%00%5C%F4%8F%BF%BD%69";
91 assert!(PctStr::new(s).is_ok());
92 let s = "No percent.";
93 assert!(PctStr::new(s).is_ok());
94 let s = "%e2%82%acwat";
95 assert!(PctStr::new(s).is_ok());
96 }
97
98 #[test]
99 fn try_from() {
100 let s = "%00%5C%F4%8F%BF%BD%69";
101 let _pcs = PctString::try_from(s).unwrap();
102 let _pcs: &PctStr = s.try_into().unwrap();
103 }
104
105 #[test]
106 fn encode_percent_always() {
107 struct NoopEncoder;
108 impl Encoder for NoopEncoder {
109 fn encode(&self, _: char) -> bool {
110 false
111 }
112 }
113 let s = "%";
114 let c = PctString::encode(s.chars(), NoopEncoder);
115 assert_eq!(c.as_str(), "%25");
116 }
117}