1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use crate::common;
use lazy_static::lazy_static;
use precis_core::profile::{PrecisFastInvocation, Profile, Rules};
use precis_core::Error;
use precis_core::{FreeformClass, StringClass};
use std::borrow::Cow;
pub struct OpaqueString {
class: FreeformClass,
}
impl OpaqueString {
pub fn new() -> Self {
Self {
class: FreeformClass {},
}
}
}
impl Default for OpaqueString {
fn default() -> Self {
OpaqueString::new()
}
}
impl Profile for OpaqueString {
fn prepare<'a>(&self, s: &'a str) -> Result<Cow<'a, str>, Error> {
let s = (!s.is_empty()).then(|| s).ok_or(Error::Invalid)?;
self.class.allows(s)?;
Ok(s.into())
}
fn enforce<'a>(&self, s: &'a str) -> Result<Cow<'a, str>, Error> {
let s = self.prepare(s)?;
let s = self.additional_mapping_rule(s)?;
let s = self.normalization_rule(s)?;
(!s.is_empty()).then(|| s).ok_or(Error::Invalid)
}
fn compare(&self, s1: &str, s2: &str) -> Result<bool, Error> {
Ok(self.enforce(s1)? == self.enforce(s2)?)
}
}
impl Rules for OpaqueString {
fn additional_mapping_rule<'a, T>(&self, s: T) -> Result<Cow<'a, str>, Error>
where
T: Into<Cow<'a, str>>,
{
let s = s.into();
match s.find(common::is_non_ascii_space) {
None => Ok(s),
Some(pos) => {
let mut res = String::from(&s[..pos]);
res.reserve(s.len() - res.len());
for c in s[pos..].chars() {
if common::is_non_ascii_space(c) {
res.push(common::SPACE);
} else {
res.push(c);
}
}
Ok(res.into())
}
}
}
fn normalization_rule<'a, T>(&self, s: T) -> Result<Cow<'a, str>, Error>
where
T: Into<Cow<'a, str>>,
{
common::normalization_form_nfc(s)
}
}
fn get_opaque_string_profile() -> &'static OpaqueString {
lazy_static! {
static ref OPAQUE_STRING: OpaqueString = OpaqueString::new();
}
&OPAQUE_STRING
}
impl PrecisFastInvocation for OpaqueString {
fn prepare(s: &str) -> Result<Cow<'_, str>, Error> {
get_opaque_string_profile().prepare(s)
}
fn enforce<'a>(s: &str) -> Result<Cow<'_, str>, Error> {
get_opaque_string_profile().enforce(s)
}
fn compare(s1: &str, s2: &str) -> Result<bool, Error> {
get_opaque_string_profile().compare(s1, s2)
}
}