1use super::{configuration::*, weight::*};
2
3use {
4 ::bytes::*,
5 kutil_std::collections::*,
6 kutil_transcoding::{bytes::*, *},
7 std::io,
8};
9
10#[derive(Clone, Debug)]
16pub struct CachedBody {
17 pub representations: FastHashMap<Encoding, Bytes>,
19}
20
21impl CachedBody {
22 pub fn new() -> Self {
24 Self { representations: FastHashMap::new() }
25 }
26
27 pub async fn new_with(
34 bytes: Bytes,
35 encoding: Encoding,
36 preferred_encoding: Encoding,
37 configuration: &EncodingConfiguration,
38 ) -> io::Result<Self> {
39 let mut representations = FastHashMap::new();
40
41 if preferred_encoding == encoding {
42 representations.insert(preferred_encoding, bytes);
44 } else if encoding == Encoding::Identity {
45 tracing::debug!("encoding to {}", preferred_encoding);
46
47 let encoded_bytes = bytes.encode(&preferred_encoding).await?;
48
49 representations.insert(preferred_encoding, encoded_bytes);
50 if configuration.keep_identity_encoding {
51 representations.insert(Encoding::Identity, bytes);
52 }
53 } else if preferred_encoding == Encoding::Identity {
54 tracing::debug!("decoding from {}", encoding);
55
56 let identity_bytes = bytes.decode(&encoding).await?;
57
58 representations.insert(Encoding::Identity, identity_bytes);
59 } else {
60 tracing::debug!("reencoding from {} to {}", encoding, preferred_encoding);
61
62 let identity_bytes = bytes.decode(&encoding).await?;
63 let encoded_bytes = identity_bytes.encode(&preferred_encoding).await?;
64
65 representations.insert(preferred_encoding, encoded_bytes);
66 if configuration.keep_identity_encoding {
67 representations.insert(Encoding::Identity, identity_bytes);
68 }
69 }
70
71 Ok(Self { representations })
72 }
73
74 pub async fn get(
85 &self,
86 encoding: &Encoding,
87 configuration: &EncodingConfiguration,
88 ) -> io::Result<(Bytes, Option<Self>)> {
89 match self.representations.get(encoding) {
90 Some(bytes) => Ok((bytes.clone(), None)),
91
92 None => match encoding {
93 Encoding::Identity => {
94 for from_encoding in ENCODINGS_BY_DECODING_COST {
96 if let Some(bytes) = self.representations.get(from_encoding) {
97 tracing::debug!("decoding from {}", from_encoding);
98
99 let identity_bytes = bytes.decode(from_encoding).await?;
100
101 let mut modified = self.clone();
102 modified.representations.insert(Encoding::Identity, identity_bytes.clone());
103
104 return Ok((identity_bytes, Some(modified)));
105 }
106 }
107
108 tracing::error!("no encodings");
110 Ok((Bytes::new(), None))
111 }
112
113 to_encoding => {
114 if let Some(identity_bytes) = self.representations.get(&Encoding::Identity) {
116 tracing::debug!("encoding to {}", to_encoding);
117
118 let bytes = identity_bytes.encode(to_encoding).await?;
119
120 let mut modified = self.clone();
121 modified.representations.insert(to_encoding.clone(), bytes.clone());
122
123 Ok((bytes, Some(modified)))
124 } else {
125 for from_encoding in ENCODINGS_BY_DECODING_COST {
126 if let Some(bytes) = self.representations.get(from_encoding) {
127 tracing::debug!("reencoding from {} to {}", from_encoding, to_encoding);
128
129 let identity_bytes = bytes.decode(from_encoding).await?;
130 let bytes = identity_bytes.encode(to_encoding).await?;
131
132 let mut modified = self.clone();
133 if configuration.keep_identity_encoding {
134 modified.representations.insert(Encoding::Identity, identity_bytes);
135 }
136 modified.representations.insert(to_encoding.clone(), bytes.clone());
137
138 return Ok((bytes, Some(modified)));
139 }
140 }
141
142 tracing::error!("no encodings");
144 Ok((Bytes::new(), None))
145 }
146 }
147 },
148 }
149 }
150}
151
152impl CacheWeight for CachedBody {
153 fn cache_weight(&self) -> usize {
154 const SELF_SIZE: usize = size_of::<CachedBody>();
155 const ENTRY_SIZE: usize = size_of::<Encoding>() + size_of::<Bytes>();
156
157 let mut size = SELF_SIZE;
158
159 for bytes in self.representations.values() {
160 size += ENTRY_SIZE + bytes.len();
161 }
162
163 size
164 }
165}