bee_block/output/feature/
mod.rs1mod issuer;
5mod metadata;
6mod sender;
7mod tag;
8
9use alloc::{boxed::Box, vec::Vec};
10
11use bitflags::bitflags;
12use derive_more::{Deref, From};
13use iterator_sorted::is_unique_sorted;
14use packable::{bounded::BoundedU8, prefix::BoxedSlicePrefix, Packable};
15
16pub use self::{issuer::IssuerFeature, metadata::MetadataFeature, sender::SenderFeature, tag::TagFeature};
17pub(crate) use self::{metadata::MetadataFeatureLength, tag::TagFeatureLength};
18use crate::{create_bitflags, Error};
19
20#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, From, Packable)]
22#[cfg_attr(
23 feature = "serde",
24 derive(serde::Serialize, serde::Deserialize),
25 serde(tag = "type", content = "data")
26)]
27#[packable(unpack_error = Error)]
28#[packable(tag_type = u8, with_error = Error::InvalidFeatureKind)]
29pub enum Feature {
30 #[packable(tag = SenderFeature::KIND)]
32 Sender(SenderFeature),
33 #[packable(tag = IssuerFeature::KIND)]
35 Issuer(IssuerFeature),
36 #[packable(tag = MetadataFeature::KIND)]
38 Metadata(MetadataFeature),
39 #[packable(tag = TagFeature::KIND)]
41 Tag(TagFeature),
42}
43
44impl Feature {
45 pub fn kind(&self) -> u8 {
47 match self {
48 Self::Sender(_) => SenderFeature::KIND,
49 Self::Issuer(_) => IssuerFeature::KIND,
50 Self::Metadata(_) => MetadataFeature::KIND,
51 Self::Tag(_) => TagFeature::KIND,
52 }
53 }
54
55 pub fn flag(&self) -> FeatureFlags {
57 match self {
58 Self::Sender(_) => FeatureFlags::SENDER,
59 Self::Issuer(_) => FeatureFlags::ISSUER,
60 Self::Metadata(_) => FeatureFlags::METADATA,
61 Self::Tag(_) => FeatureFlags::TAG,
62 }
63 }
64}
65
66create_bitflags!(
67 pub FeatureFlags,
69 u16,
70 [
71 (SENDER, SenderFeature),
72 (ISSUER, IssuerFeature),
73 (METADATA, MetadataFeature),
74 (TAG, TagFeature),
75 ]
76);
77
78pub(crate) type FeatureCount = BoundedU8<0, { Features::COUNT_MAX }>;
79
80#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Deref, Packable)]
82#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
83#[packable(unpack_error = Error, with = |e| e.unwrap_item_err_or_else(|p| Error::InvalidFeatureCount(p.into())))]
84pub struct Features(#[packable(verify_with = verify_unique_sorted)] BoxedSlicePrefix<Feature, FeatureCount>);
85
86impl TryFrom<Vec<Feature>> for Features {
87 type Error = Error;
88
89 #[inline(always)]
90 fn try_from(features: Vec<Feature>) -> Result<Self, Self::Error> {
91 Self::new(features)
92 }
93}
94
95impl IntoIterator for Features {
96 type Item = Feature;
97 type IntoIter = alloc::vec::IntoIter<Self::Item>;
98
99 fn into_iter(self) -> Self::IntoIter {
100 Vec::from(Into::<Box<[Feature]>>::into(self.0)).into_iter()
101 }
102}
103
104impl Features {
105 pub const COUNT_MAX: u8 = 4;
107
108 pub fn new(features: Vec<Feature>) -> Result<Self, Error> {
110 let mut features = BoxedSlicePrefix::<Feature, FeatureCount>::try_from(features.into_boxed_slice())
111 .map_err(Error::InvalidFeatureCount)?;
112
113 features.sort_by_key(Feature::kind);
114 verify_unique_sorted::<true>(&features, &())?;
116
117 Ok(Self(features))
118 }
119
120 #[inline(always)]
122 pub fn get(&self, key: u8) -> Option<&Feature> {
123 self.0
124 .binary_search_by_key(&key, Feature::kind)
125 .map(|index| &self.0[index])
127 .ok()
128 }
129
130 pub fn sender(&self) -> Option<&SenderFeature> {
132 if let Some(Feature::Sender(sender)) = self.get(SenderFeature::KIND) {
133 Some(sender)
134 } else {
135 None
136 }
137 }
138
139 pub fn issuer(&self) -> Option<&IssuerFeature> {
141 if let Some(Feature::Issuer(issuer)) = self.get(IssuerFeature::KIND) {
142 Some(issuer)
143 } else {
144 None
145 }
146 }
147
148 pub fn metadata(&self) -> Option<&MetadataFeature> {
150 if let Some(Feature::Metadata(metadata)) = self.get(MetadataFeature::KIND) {
151 Some(metadata)
152 } else {
153 None
154 }
155 }
156
157 pub fn tag(&self) -> Option<&TagFeature> {
159 if let Some(Feature::Tag(tag)) = self.get(TagFeature::KIND) {
160 Some(tag)
161 } else {
162 None
163 }
164 }
165}
166
167#[inline]
168fn verify_unique_sorted<const VERIFY: bool>(features: &[Feature], _: &()) -> Result<(), Error> {
169 if VERIFY && !is_unique_sorted(features.iter().map(Feature::kind)) {
170 Err(Error::FeaturesNotUniqueSorted)
171 } else {
172 Ok(())
173 }
174}
175
176pub(crate) fn verify_allowed_features(features: &Features, allowed_features: FeatureFlags) -> Result<(), Error> {
177 for (index, feature) in features.iter().enumerate() {
178 if !allowed_features.contains(feature.flag()) {
179 return Err(Error::UnallowedFeature {
180 index,
181 kind: feature.kind(),
182 });
183 }
184 }
185
186 Ok(())
187}
188
189#[cfg(test)]
190mod test {
191 use super::*;
192
193 #[test]
194 fn all_flags_present() {
195 assert_eq!(
196 FeatureFlags::ALL_FLAGS,
197 &[
198 FeatureFlags::SENDER,
199 FeatureFlags::ISSUER,
200 FeatureFlags::METADATA,
201 FeatureFlags::TAG
202 ]
203 );
204 }
205}
206
207#[cfg(feature = "dto")]
208#[allow(missing_docs)]
209pub mod dto {
210 use serde::{Deserialize, Serialize, Serializer};
211 use serde_json::Value;
212
213 pub use self::{
214 issuer::dto::IssuerFeatureDto, metadata::dto::MetadataFeatureDto, sender::dto::SenderFeatureDto,
215 tag::dto::TagFeatureDto,
216 };
217 use super::*;
218 use crate::error::dto::DtoError;
219
220 #[derive(Clone, Debug, Eq, PartialEq, From)]
221 pub enum FeatureDto {
222 Sender(SenderFeatureDto),
224 Issuer(IssuerFeatureDto),
226 Metadata(MetadataFeatureDto),
228 Tag(TagFeatureDto),
230 }
231
232 impl<'de> Deserialize<'de> for FeatureDto {
233 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
234 let value = Value::deserialize(d)?;
235 Ok(
236 match value
237 .get("type")
238 .and_then(Value::as_u64)
239 .ok_or_else(|| serde::de::Error::custom("invalid feature type"))? as u8
240 {
241 SenderFeature::KIND => {
242 FeatureDto::Sender(SenderFeatureDto::deserialize(value).map_err(|e| {
243 serde::de::Error::custom(format!("cannot deserialize sender feature: {}", e))
244 })?)
245 }
246 IssuerFeature::KIND => {
247 FeatureDto::Issuer(IssuerFeatureDto::deserialize(value).map_err(|e| {
248 serde::de::Error::custom(format!("cannot deserialize issuer feature: {}", e))
249 })?)
250 }
251 MetadataFeature::KIND => {
252 FeatureDto::Metadata(MetadataFeatureDto::deserialize(value).map_err(|e| {
253 serde::de::Error::custom(format!("cannot deserialize metadata feature: {}", e))
254 })?)
255 }
256 TagFeature::KIND => FeatureDto::Tag(
257 TagFeatureDto::deserialize(value)
258 .map_err(|e| serde::de::Error::custom(format!("cannot deserialize tag feature: {}", e)))?,
259 ),
260 _ => return Err(serde::de::Error::custom("invalid feature type")),
261 },
262 )
263 }
264 }
265
266 impl Serialize for FeatureDto {
267 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
268 where
269 S: Serializer,
270 {
271 #[derive(Serialize)]
272 #[serde(untagged)]
273 enum FeatureDto_<'a> {
274 T1(&'a SenderFeatureDto),
275 T2(&'a IssuerFeatureDto),
276 T3(&'a MetadataFeatureDto),
277 T4(&'a TagFeatureDto),
278 }
279 #[derive(Serialize)]
280 struct TypedFeature<'a> {
281 #[serde(flatten)]
282 feature: FeatureDto_<'a>,
283 }
284 let feature = match self {
285 FeatureDto::Sender(o) => TypedFeature {
286 feature: FeatureDto_::T1(o),
287 },
288 FeatureDto::Issuer(o) => TypedFeature {
289 feature: FeatureDto_::T2(o),
290 },
291 FeatureDto::Metadata(o) => TypedFeature {
292 feature: FeatureDto_::T3(o),
293 },
294 FeatureDto::Tag(o) => TypedFeature {
295 feature: FeatureDto_::T4(o),
296 },
297 };
298 feature.serialize(serializer)
299 }
300 }
301
302 impl From<&Feature> for FeatureDto {
303 fn from(value: &Feature) -> Self {
304 match value {
305 Feature::Sender(v) => Self::Sender(SenderFeatureDto {
306 kind: SenderFeature::KIND,
307 address: v.address().into(),
308 }),
309 Feature::Issuer(v) => Self::Issuer(IssuerFeatureDto {
310 kind: IssuerFeature::KIND,
311 address: v.address().into(),
312 }),
313 Feature::Metadata(v) => Self::Metadata(MetadataFeatureDto {
314 kind: MetadataFeature::KIND,
315 data: v.to_string(),
316 }),
317 Feature::Tag(v) => Self::Tag(TagFeatureDto {
318 kind: TagFeature::KIND,
319 tag: v.to_string(),
320 }),
321 }
322 }
323 }
324
325 impl TryFrom<&FeatureDto> for Feature {
326 type Error = DtoError;
327
328 fn try_from(value: &FeatureDto) -> Result<Self, Self::Error> {
329 Ok(match value {
330 FeatureDto::Sender(v) => Self::Sender(SenderFeature::new((&v.address).try_into()?)),
331 FeatureDto::Issuer(v) => Self::Issuer(IssuerFeature::new((&v.address).try_into()?)),
332 FeatureDto::Metadata(v) => Self::Metadata(MetadataFeature::new(
333 prefix_hex::decode(&v.data).map_err(|_e| DtoError::InvalidField("MetadataFeature"))?,
334 )?),
335 FeatureDto::Tag(v) => Self::Tag(TagFeature::new(
336 prefix_hex::decode(&v.tag).map_err(|_e| DtoError::InvalidField("TagFeature"))?,
337 )?),
338 })
339 }
340 }
341
342 impl FeatureDto {
343 pub fn kind(&self) -> u8 {
345 match self {
346 Self::Sender(_) => SenderFeature::KIND,
347 Self::Issuer(_) => IssuerFeature::KIND,
348 Self::Metadata(_) => MetadataFeature::KIND,
349 Self::Tag(_) => TagFeature::KIND,
350 }
351 }
352 }
353}