1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
12#[serde(rename_all = "lowercase")]
13pub enum Algorithm {
14 None,
16 #[default]
23 M2M,
24 TokenNative,
32 Brotli,
39}
40
41impl Algorithm {
42 pub fn prefix(&self) -> &'static str {
44 match self {
45 Algorithm::None => "",
46 Algorithm::M2M => "#M2M|1|",
47 Algorithm::TokenNative => "#TK|",
48 Algorithm::Brotli => "#M2M[v3.0]|DATA:",
49 }
50 }
51
52 pub fn from_prefix(content: &str) -> Option<Self> {
54 if content.starts_with("#M2M|1|") {
55 Some(Algorithm::M2M)
56 } else if content.starts_with("#TK|") {
57 Some(Algorithm::TokenNative)
58 } else if content.starts_with("#M2M[v3.0]|") {
59 Some(Algorithm::Brotli)
60 } else {
61 None
62 }
63 }
64
65 pub fn name(&self) -> &'static str {
67 match self {
68 Algorithm::None => "NONE",
69 Algorithm::M2M => "M2M",
70 Algorithm::TokenNative => "TOKEN_NATIVE",
71 Algorithm::Brotli => "BROTLI",
72 }
73 }
74
75 pub fn all() -> &'static [Algorithm] {
77 &[
78 Algorithm::M2M,
79 Algorithm::TokenNative,
80 Algorithm::Brotli,
81 Algorithm::None,
82 ]
83 }
84}
85
86impl std::fmt::Display for Algorithm {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 write!(f, "{}", self.name())
89 }
90}
91
92#[derive(Debug, Clone)]
94pub struct CompressionResult {
95 pub data: String,
97 pub algorithm: Algorithm,
99 pub original_bytes: usize,
101 pub compressed_bytes: usize,
103 pub original_tokens: Option<usize>,
105 pub compressed_tokens: Option<usize>,
107}
108
109impl CompressionResult {
110 pub fn new(
112 data: String,
113 algorithm: Algorithm,
114 original_bytes: usize,
115 compressed_bytes: usize,
116 ) -> Self {
117 Self {
118 data,
119 algorithm,
120 original_bytes,
121 compressed_bytes,
122 original_tokens: None,
123 compressed_tokens: None,
124 }
125 }
126
127 pub fn with_tokens(mut self, original: usize, compressed: usize) -> Self {
129 self.original_tokens = Some(original);
130 self.compressed_tokens = Some(compressed);
131 self
132 }
133
134 pub fn byte_ratio(&self) -> f64 {
136 if self.compressed_bytes == 0 {
137 0.0
138 } else {
139 self.original_bytes as f64 / self.compressed_bytes as f64
140 }
141 }
142
143 pub fn token_savings_percent(&self) -> Option<f64> {
145 match (self.original_tokens, self.compressed_tokens) {
146 (Some(orig), Some(comp)) if orig > 0 => {
147 Some((orig as f64 - comp as f64) / orig as f64 * 100.0)
148 },
149 _ => None,
150 }
151 }
152
153 pub fn is_beneficial(&self) -> bool {
155 match (self.original_tokens, self.compressed_tokens) {
156 (Some(orig), Some(comp)) => comp < orig,
157 _ => self.compressed_bytes < self.original_bytes,
158 }
159 }
160}