1use serde::{Deserialize, Serialize};
7use std::fmt;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
26#[repr(transparent)]
27pub struct Modifier(pub u16);
28
29impl Modifier {
30 pub const VOICE_NEUTRAL: Self = Self(0x0000);
32 pub const VOICE_FORMAL: Self = Self(0x4000);
33 pub const VOICE_CASUAL: Self = Self(0x8000);
34 pub const VOICE_TECHNICAL: Self = Self(0xC000);
35
36 pub const TONE_NEUTRAL: Self = Self(0x0000);
38 pub const TONE_POSITIVE: Self = Self(0x1000);
39 pub const TONE_EMPATHETIC: Self = Self(0x2000);
40 pub const TONE_CAUTIOUS: Self = Self(0x3000);
41
42 pub const WARMTH_COLD: Self = Self(0x0000);
44 pub const WARMTH_NEUTRAL: Self = Self(0x0400);
45 pub const WARMTH_WARM: Self = Self(0x0800);
46 pub const WARMTH_VERY_WARM: Self = Self(0x0C00);
47
48 pub const FORMAT_PROSE: Self = Self(0x0000);
50 pub const FORMAT_BULLETED: Self = Self(0x0100);
51 pub const FORMAT_NUMBERED: Self = Self(0x0200);
52 pub const FORMAT_STRUCTURED: Self = Self(0x0300);
53
54 pub const ACCURACY_LOW: Self = Self(0x0000);
56 pub const ACCURACY_MEDIUM: Self = Self(0x0040);
57 pub const ACCURACY_HIGH: Self = Self(0x0080);
58 pub const ACCURACY_VERIFIED: Self = Self(0x00C0);
59
60 pub const URGENCY_LOW: Self = Self(0x0000);
62 pub const URGENCY_NORMAL: Self = Self(0x0010);
63 pub const URGENCY_HIGH: Self = Self(0x0020);
64 pub const URGENCY_CRITICAL: Self = Self(0x0030);
65
66 const VOICE_MASK: u16 = 0xC000;
68 const TONE_MASK: u16 = 0x3000;
69 const WARMTH_MASK: u16 = 0x0C00;
70 const FORMAT_MASK: u16 = 0x0300;
71 const ACCURACY_MASK: u16 = 0x00C0;
72 const URGENCY_MASK: u16 = 0x0030;
73
74 #[inline]
76 pub const fn from_u16(value: u16) -> Self {
77 Self(value)
78 }
79
80 #[inline]
82 pub const fn as_u16(&self) -> u16 {
83 self.0
84 }
85
86 #[inline]
88 pub const fn voice(&self) -> Voice {
89 match self.0 & Self::VOICE_MASK {
90 0x0000 => Voice::Neutral,
91 0x4000 => Voice::Formal,
92 0x8000 => Voice::Casual,
93 _ => Voice::Technical,
94 }
95 }
96
97 #[inline]
99 pub const fn tone(&self) -> Tone {
100 match self.0 & Self::TONE_MASK {
101 0x0000 => Tone::Neutral,
102 0x1000 => Tone::Positive,
103 0x2000 => Tone::Empathetic,
104 _ => Tone::Cautious,
105 }
106 }
107
108 #[inline]
110 pub const fn warmth(&self) -> Warmth {
111 match self.0 & Self::WARMTH_MASK {
112 0x0000 => Warmth::Cold,
113 0x0400 => Warmth::Neutral,
114 0x0800 => Warmth::Warm,
115 _ => Warmth::VeryWarm,
116 }
117 }
118
119 #[inline]
121 pub const fn format(&self) -> Format {
122 match self.0 & Self::FORMAT_MASK {
123 0x0000 => Format::Prose,
124 0x0100 => Format::Bulleted,
125 0x0200 => Format::Numbered,
126 _ => Format::Structured,
127 }
128 }
129
130 #[inline]
132 pub const fn accuracy(&self) -> Accuracy {
133 match self.0 & Self::ACCURACY_MASK {
134 0x0000 => Accuracy::Low,
135 0x0040 => Accuracy::Medium,
136 0x0080 => Accuracy::High,
137 _ => Accuracy::Verified,
138 }
139 }
140
141 #[inline]
143 pub const fn urgency(&self) -> Urgency {
144 match self.0 & Self::URGENCY_MASK {
145 0x0000 => Urgency::Low,
146 0x0010 => Urgency::Normal,
147 0x0020 => Urgency::High,
148 _ => Urgency::Critical,
149 }
150 }
151
152 #[inline]
154 pub const fn with_voice(self, voice: Voice) -> Self {
155 let voice_bits = match voice {
156 Voice::Neutral => 0x0000,
157 Voice::Formal => 0x4000,
158 Voice::Casual => 0x8000,
159 Voice::Technical => 0xC000,
160 };
161 Self((self.0 & !Self::VOICE_MASK) | voice_bits)
162 }
163
164 #[inline]
166 pub const fn with_tone(self, tone: Tone) -> Self {
167 let tone_bits = match tone {
168 Tone::Neutral => 0x0000,
169 Tone::Positive => 0x1000,
170 Tone::Empathetic => 0x2000,
171 Tone::Cautious => 0x3000,
172 };
173 Self((self.0 & !Self::TONE_MASK) | tone_bits)
174 }
175
176 #[inline]
178 pub const fn with_warmth(self, warmth: Warmth) -> Self {
179 let warmth_bits = match warmth {
180 Warmth::Cold => 0x0000,
181 Warmth::Neutral => 0x0400,
182 Warmth::Warm => 0x0800,
183 Warmth::VeryWarm => 0x0C00,
184 };
185 Self((self.0 & !Self::WARMTH_MASK) | warmth_bits)
186 }
187
188 #[inline]
190 pub const fn with_format(self, format: Format) -> Self {
191 let format_bits = match format {
192 Format::Prose => 0x0000,
193 Format::Bulleted => 0x0100,
194 Format::Numbered => 0x0200,
195 Format::Structured => 0x0300,
196 };
197 Self((self.0 & !Self::FORMAT_MASK) | format_bits)
198 }
199
200 #[inline]
202 pub const fn with_accuracy(self, accuracy: Accuracy) -> Self {
203 let accuracy_bits = match accuracy {
204 Accuracy::Low => 0x0000,
205 Accuracy::Medium => 0x0040,
206 Accuracy::High => 0x0080,
207 Accuracy::Verified => 0x00C0,
208 };
209 Self((self.0 & !Self::ACCURACY_MASK) | accuracy_bits)
210 }
211
212 #[inline]
214 pub const fn with_urgency(self, urgency: Urgency) -> Self {
215 let urgency_bits = match urgency {
216 Urgency::Low => 0x0000,
217 Urgency::Normal => 0x0010,
218 Urgency::High => 0x0020,
219 Urgency::Critical => 0x0030,
220 };
221 Self((self.0 & !Self::URGENCY_MASK) | urgency_bits)
222 }
223
224 pub const fn crisis() -> Self {
226 Self(0x0000)
227 .with_tone(Tone::Empathetic)
228 .with_warmth(Warmth::VeryWarm)
229 .with_urgency(Urgency::High)
230 .with_accuracy(Accuracy::High)
231 }
232
233 pub const fn professional() -> Self {
235 Self(0x0000)
236 .with_voice(Voice::Formal)
237 .with_warmth(Warmth::Neutral)
238 .with_accuracy(Accuracy::High)
239 .with_urgency(Urgency::Normal)
240 }
241
242 pub const fn friendly() -> Self {
244 Self(0x0000)
245 .with_voice(Voice::Casual)
246 .with_tone(Tone::Positive)
247 .with_warmth(Warmth::Warm)
248 .with_urgency(Urgency::Normal)
249 }
250}
251
252impl Default for Modifier {
253 fn default() -> Self {
254 Self(0x0400 | 0x0040 | 0x0010) }
257}
258
259impl fmt::Display for Modifier {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 write!(
262 f,
263 "MOD(0x{:04X}: {:?}/{:?}/{:?}/{:?})",
264 self.0,
265 self.voice(),
266 self.tone(),
267 self.warmth(),
268 self.format()
269 )
270 }
271}
272
273impl From<u16> for Modifier {
274 fn from(value: u16) -> Self {
275 Self(value)
276 }
277}
278
279impl From<Modifier> for u16 {
280 fn from(modifier: Modifier) -> Self {
281 modifier.0
282 }
283}
284
285#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
289pub enum Voice {
290 Neutral,
292 Formal,
294 Casual,
296 Technical,
298}
299
300#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
302pub enum Tone {
303 Neutral,
305 Positive,
307 Empathetic,
309 Cautious,
311}
312
313#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
315pub enum Warmth {
316 Cold,
318 Neutral,
320 Warm,
322 VeryWarm,
324}
325
326#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
328pub enum Format {
329 Prose,
331 Bulleted,
333 Numbered,
335 Structured,
337}
338
339#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
341pub enum Accuracy {
342 Low,
344 Medium,
346 High,
348 Verified,
350}
351
352#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
354pub enum Urgency {
355 Low,
357 Normal,
359 High,
361 Critical,
363}
364
365#[cfg(test)]
366mod tests {
367 use super::*;
368
369 #[test]
370 fn test_default_modifier() {
371 let m = Modifier::default();
372 assert_eq!(m.voice(), Voice::Neutral);
373 assert_eq!(m.tone(), Tone::Neutral);
374 assert_eq!(m.warmth(), Warmth::Neutral);
375 assert_eq!(m.format(), Format::Prose);
376 assert_eq!(m.accuracy(), Accuracy::Medium);
377 assert_eq!(m.urgency(), Urgency::Normal);
378 }
379
380 #[test]
381 fn test_field_extraction() {
382 let m = Modifier::from_u16(0xA440);
384 assert_eq!(m.voice(), Voice::Casual);
385 assert_eq!(m.tone(), Tone::Empathetic);
386 assert_eq!(m.warmth(), Warmth::Neutral);
387 assert_eq!(m.accuracy(), Accuracy::Medium);
388 }
389
390 #[test]
391 fn test_field_setting() {
392 let m = Modifier::default()
393 .with_voice(Voice::Formal)
394 .with_tone(Tone::Empathetic)
395 .with_warmth(Warmth::VeryWarm)
396 .with_format(Format::Bulleted);
397
398 assert_eq!(m.voice(), Voice::Formal);
399 assert_eq!(m.tone(), Tone::Empathetic);
400 assert_eq!(m.warmth(), Warmth::VeryWarm);
401 assert_eq!(m.format(), Format::Bulleted);
402 }
403
404 #[test]
405 fn test_crisis_modifier() {
406 let m = Modifier::crisis();
407 assert_eq!(m.tone(), Tone::Empathetic);
408 assert_eq!(m.warmth(), Warmth::VeryWarm);
409 assert_eq!(m.urgency(), Urgency::High);
410 assert_eq!(m.accuracy(), Accuracy::High);
411 }
412
413 #[test]
414 fn test_preset_modifiers() {
415 let pro = Modifier::professional();
416 assert_eq!(pro.voice(), Voice::Formal);
417
418 let friendly = Modifier::friendly();
419 assert_eq!(friendly.voice(), Voice::Casual);
420 assert_eq!(friendly.warmth(), Warmth::Warm);
421 }
422
423 #[test]
424 fn test_serialization() {
425 let modifier = Modifier::crisis();
426 let json = serde_json::to_string(&modifier).unwrap();
427 let deserialized: Modifier = serde_json::from_str(&json).unwrap();
428 assert_eq!(modifier, deserialized);
429 }
430}