salps/
lib.rs

1
2pub trait Rand {
3	fn next(&mut self) -> f64;
4}
5
6fn util_range(rng: &mut impl Rand, range: Option<(u32, Option<u32>)>, default_min: u32, default_max: u32) -> u32 {
7	match range.unwrap_or((default_min, Some(default_max))) {
8		(x, None) => x,
9		(x, Some(y)) => {
10			let y = y.max(x);
11
12			let x = x as f64;
13			let y = y as f64;
14
15			(rng.next() * (y - x) + x) as u32
16		}
17	}
18}
19
20pub struct Config {
21	pub paragraph_len: Option<(u32, Option<u32>)>,
22	pub sentence_len: Option<(u32, Option<u32>)>,
23	pub word_len: Option<(u32, Option<u32>)>,
24}
25impl Default for Config {
26	fn default() -> Self {
27		Self {
28			paragraph_len: None,
29			sentence_len: None,
30			word_len: None,
31		}
32	}
33}
34
35
36const FULL: &'static [&str] = &[
37	"a",
38	"b",
39	"c",
40	"d",
41	"e",
42	"f",
43	"g",
44	"h",
45	"i",
46	"j",
47	"k",
48	"l",
49	"m",
50	"n",
51	"o",
52	"p",
53	"q",
54	"r",
55	"s",
56	"t",
57	"u",
58	"v",
59	"w",
60	"x",
61	"y",
62	"z",
63];
64
65const VOWEL: &'static [&str] = &[
66	"a",
67	"e",
68	"i",
69	"o",
70	"u",
71];
72
73const FILL: &'static [&str] = &[
74	"b",
75	"c",
76	"d",
77	"f",
78	"g",
79	"h",
80	"j",
81	"k",
82	"l",
83	"m",
84	"n",
85	"p",
86	"q",
87	"r",
88	"s",
89	"t",
90	"v",
91	"w",
92	"x",
93	"y",
94	"z",
95];
96
97const LAC: &'static [&str] = &[
98	"s",
99	"l",
100	"w",
101];
102
103enum Kind {
104	None,
105	Consonant,
106	Vowel,
107	Lac,
108}
109
110fn word_raw(rng: &mut impl Rand, config: &Config) -> String {
111	let mut out = String::new();
112
113	let len = util_range(rng, config.word_len, 2, 12);
114
115	let mut state = Kind::None;
116
117	let go = |a: &[&'static str], r: f64| {
118		a[(r * a.len() as f64) as usize]
119	};
120
121	for _ in 0..len {
122		out += match state {
123			Kind::None => {
124				state = Kind::Consonant;
125				go(FULL, rng.next())
126			},
127			Kind::Consonant => if rng.next() < 0.33 {
128				state = Kind::Lac;
129				go(LAC, rng.next())
130			} else {
131				state = Kind::Vowel;
132				go(VOWEL, rng.next())
133			},
134			Kind::Lac => {
135				state = Kind::Vowel;
136				go(VOWEL, rng.next())
137			},
138			Kind::Vowel => if rng.next() < 0.25 {
139				state = Kind::Vowel;
140				go(VOWEL, rng.next())
141			} else {
142				state = Kind::Consonant;
143				go(FILL, rng.next())
144			}
145		}
146	}
147
148	out
149}
150
151/// generates a word.
152pub fn word(rng: &mut impl Rand, config: &Config) -> String {
153	word_raw(rng, config)
154}
155
156
157fn sentence_raw(rng: &mut impl Rand, config: &Config) -> String {
158	let mut out = String::new();
159
160	let len = util_range(rng, config.sentence_len, 2, 14);
161
162	for i in 0..len {
163		out += word_raw(rng, config).as_str();
164		if i == len - 1 {
165			match rng.next() {
166				0.00..0.05 => out += "!",
167				0.05..0.07 => out += "!!",
168				0.07..0.14 => out += "?",
169				0.14..0.25 => out += " :3",
170				0.25..0.27 => out += "...",
171				_ => out += ".",
172			}
173		} else if rng.next() <= 0.08 {
174			out += ", ";
175		} else {
176			out += " ";
177		}
178	}
179
180	out
181}
182
183/// generates words to form a "sentence".
184/// the sentence will end with some form of punctuation,
185/// and may contain commas.
186pub fn sentence(rng: &mut impl Rand, config: &Config) -> String {
187	sentence_raw(rng, config)
188}
189
190
191fn paragraph_raw(rng: &mut impl Rand, config: &Config) -> String {
192	let mut out = String::new();
193
194	let len = util_range(rng, config.paragraph_len, 6, 12);
195
196	for _ in 0..len {
197		out += sentence_raw(rng, config).as_str();
198		out += " ";
199	}
200
201	out
202}
203
204/// generates a sentences to form a "paragraph".
205pub fn paragraph(rng: &mut impl Rand, config: &Config) -> String {
206	paragraph_raw(rng, config)
207}
208
209
210#[cfg(test)]
211mod test {
212	struct Fake;
213	impl crate::Rand for Fake {
214		fn next(&mut self) -> f64 {
215			0.0
216		}
217	}
218	
219	#[test]
220	fn test() {
221		let word = crate::word(&mut Fake, &crate::Config {
222			word_len: Some((4, None)),
223			..Default::default()
224		});
225		assert_eq!(word.len(), 4);
226	}
227}
228