1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use crate::*;

/// Configuration of a TP buffers maximum allowed size and initial allocated buffer size.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct TpBufConfig {
    /// Number of bytes that should be allocated to store payload
    /// when a new [`TpBuf`] gets created.
    pub tp_buffer_start_payload_alloc_len: usize,

    /// Maximum allowed payload length (in bytes) of the final reconstructed packet.
    tp_max_payload_len: u32,
}

impl TpBufConfig {
    /// Maximum representable payload len in a TP packet.
    ///
    /// This is determined by the maximum value the length
    /// field in the SOMEIP header can take - 8 bytes
    pub const MAX_TP_PAYLOAD_LEN: u32 = u32::MAX - (SOMEIP_HEADER_LENGTH as u32);

    /// Maximum allowed payload length (in bytes) of the final reconstructed packet.
    #[inline]
    pub fn tp_max_payload_len(&self) -> u32 {
        self.tp_max_payload_len
    }

    /// Creates a new config with the given initial allocated and maximum allowed payload size.
    ///
    /// # Example
    ///
    /// As long as you don't set the max_payload_len to more then
    /// `TpBufConfig::MAX_TP_PAYLOAD_LEN` (0xFFFFFFFF - 16):
    ///
    /// ```
    /// use someip_parse::TpBufConfig;
    ///
    /// let config = TpBufConfig::new(
    ///     // start alloc size
    ///     1024,
    ///     // maximum allowed size
    ///     // (if you have knowledge about the maximum message size,
    ///     // insert that here and above)
    ///     TpBufConfig::MAX_TP_PAYLOAD_LEN
    /// ).unwrap();
    /// ```
    ///
    /// construction will only fail if you set an upper lenght greater
    /// then `TpBufConfig::MAX_TP_PAYLOAD_LEN`:
    ///
    /// ```
    /// use someip_parse::{TpBufConfig, err::TpBufConfigError::*};
    ///
    /// assert_eq!(
    ///     TpBufConfig::new(1024, TpBufConfig::MAX_TP_PAYLOAD_LEN + 1),
    ///     Err(MaxPayloadLenTooBig{
    ///         allowed_max: TpBufConfig::MAX_TP_PAYLOAD_LEN,
    ///         actual: TpBufConfig::MAX_TP_PAYLOAD_LEN + 1,
    ///     })
    /// );
    /// ```
    pub fn new(
        tp_buffer_start_payload_alloc_len: usize,
        tp_max_payload_len: u32,
    ) -> Result<TpBufConfig, err::TpBufConfigError> {
        if tp_max_payload_len > Self::MAX_TP_PAYLOAD_LEN {
            use err::TpBufConfigError::*;
            Err(MaxPayloadLenTooBig {
                allowed_max: Self::MAX_TP_PAYLOAD_LEN,
                actual: tp_max_payload_len,
            })
        } else {
            Ok(TpBufConfig {
                tp_buffer_start_payload_alloc_len,
                tp_max_payload_len,
            })
        }
    }
}

impl core::default::Default for TpBufConfig {
    fn default() -> Self {
        Self {
            tp_buffer_start_payload_alloc_len: 0x40000,
            tp_max_payload_len: TpBufConfig::MAX_TP_PAYLOAD_LEN,
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn debug_clone_eq() {
        let config = TpBufConfig::new(1024, 1024).unwrap();
        let _ = format!("{:?}", config);
        assert_eq!(config, config.clone());
        assert_eq!(config.cmp(&config), core::cmp::Ordering::Equal);
        assert_eq!(
            config.partial_cmp(&config),
            Some(core::cmp::Ordering::Equal)
        );

        use core::hash::{Hash, Hasher};
        use std::collections::hash_map::DefaultHasher;
        let h1 = {
            let mut h = DefaultHasher::new();
            config.hash(&mut h);
            h.finish()
        };
        let h2 = {
            let mut h = DefaultHasher::new();
            config.clone().hash(&mut h);
            h.finish()
        };
        assert_eq!(h1, h2);
    }

    #[test]
    fn default() {
        let actual: TpBufConfig = Default::default();
        assert_eq!(0x40000, actual.tp_buffer_start_payload_alloc_len);
        assert_eq!(TpBufConfig::MAX_TP_PAYLOAD_LEN, actual.tp_max_payload_len);
    }

    #[test]
    fn new() {
        {
            let actual = TpBufConfig::new(
                // start alloc size
                1024,
                // maximum allowed size
                // (if you have knowledge about the maximum message size,
                // insert that here and above)
                TpBufConfig::MAX_TP_PAYLOAD_LEN,
            )
            .unwrap();
            assert_eq!(actual.tp_buffer_start_payload_alloc_len, 1024);
            assert_eq!(actual.tp_max_payload_len(), TpBufConfig::MAX_TP_PAYLOAD_LEN);
        }

        use crate::err::TpBufConfigError::*;
        assert_eq!(
            TpBufConfig::new(1024, TpBufConfig::MAX_TP_PAYLOAD_LEN + 1),
            Err(MaxPayloadLenTooBig {
                allowed_max: TpBufConfig::MAX_TP_PAYLOAD_LEN,
                actual: TpBufConfig::MAX_TP_PAYLOAD_LEN + 1,
            })
        );
    }
}