async_coap/
etag.rs

1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16use super::util::encode_u32;
17use core::convert::From;
18use core::ops::Deref;
19
20/// Type for holding the value of an ETag option.
21#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone, Ord, PartialOrd)]
22pub struct ETag {
23    len: u8,
24    bytes: [u8; 8],
25}
26
27impl ETag {
28    /// Describes the maximum length of an ETag (8 bytes).
29    pub const MAX_LEN: usize = 8;
30
31    /// Constant representing an empty ETag.
32    pub const EMPTY: ETag = ETag {
33        len: 0u8,
34        bytes: [0; 8],
35    };
36
37    /// Creates a new ETag instance from the given byte slice.
38    pub fn new(x: &[u8]) -> ETag {
39        ETag::from(x)
40    }
41
42    /// Returns the length of this ETag in bytes.
43    pub fn len(&self) -> usize {
44        self.len as usize
45    }
46
47    /// Returns true if the length of this ETag is zero.
48    pub fn is_empty(&self) -> bool {
49        self.len == 0
50    }
51
52    /// Returns the value of this ETag as a byte slice.
53    pub fn as_bytes(&self) -> &[u8] {
54        &self.bytes[..self.len as usize]
55    }
56}
57
58impl std::fmt::Display for ETag {
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        for b in self.as_bytes() {
61            write!(f, "{:02X}", b)?;
62        }
63        Ok(())
64    }
65}
66
67impl Default for ETag {
68    fn default() -> Self {
69        ETag::EMPTY
70    }
71}
72
73impl Deref for ETag {
74    type Target = [u8];
75
76    fn deref(&self) -> &Self::Target {
77        self.as_bytes()
78    }
79}
80
81impl core::cmp::PartialEq<[u8]> for ETag {
82    fn eq(&self, other: &[u8]) -> bool {
83        self.as_bytes() == other
84    }
85}
86
87impl core::convert::From<u32> for ETag {
88    fn from(x: u32) -> Self {
89        let mut bytes = [0u8; 8];
90        let len = encode_u32(x, &mut bytes).len();
91        ETag {
92            len: len as u8,
93            bytes,
94        }
95    }
96}
97
98impl core::convert::From<i32> for ETag {
99    fn from(x: i32) -> Self {
100        core::convert::Into::into(x as u32)
101    }
102}
103
104impl core::convert::From<u16> for ETag {
105    fn from(x: u16) -> Self {
106        core::convert::Into::into(x as u32)
107    }
108}
109
110impl core::convert::From<&[u8]> for ETag {
111    // Note: this will panic if x is too big.
112    fn from(x: &[u8]) -> Self {
113        let mut bytes = [0u8; 8];
114        let len = x.len();
115        bytes[..len].copy_from_slice(x);
116        ETag {
117            len: len as u8,
118            bytes,
119        }
120    }
121}