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
use coap_message_0_3::{
    error::RenderableOnMinimal,
    Code,
    MessageOption,
    MinimalWritableMessage,
    MutableWritableMessage,
    ReadableMessage,
    WithSortedOptions,
};

use crate::error::NumericError;

/// Thin wrapper around NumericError that can render and satisfies all conversion requirements
#[derive(Debug)]
pub struct Error(NumericError);

impl From<NumericError> for Error {
    fn from(e: NumericError) -> Error {
        Error(e)
    }
}

impl From<core::convert::Infallible> for Error {
    fn from(e: core::convert::Infallible) -> Error {
        match e {}
    }
}

impl RenderableOnMinimal for Error {
    type Error<IE: RenderableOnMinimal + core::fmt::Debug> = IE;
    fn render<M: MinimalWritableMessage>(self, msg: &mut M) -> Result<(), M::UnionError> {
        msg.set_code(Code::new(coap_numbers::code::INTERNAL_SERVER_ERROR)?);
        Ok(())
    }
}

impl<'a> MessageOption for super::MessageOption<'a> {
    fn number(&self) -> u16 {
        self.number
    }

    fn value(&self) -> &[u8] {
        self.value
    }
}

impl WithSortedOptions for super::PacketBuffer {
    // valid because gcoap just reads options from the message where they are stored in sequence
}

impl ReadableMessage for super::PacketBuffer {
    type Code = u8;
    type OptionsIter<'a> = super::OptionsIterator<'a>;
    type MessageOption<'a> = super::MessageOption<'a>;

    fn code(&self) -> Self::Code {
        self.get_code_raw()
    }

    fn payload(&self) -> &[u8] {
        self.payload()
    }

    fn options(&self) -> Self::OptionsIter<'_> {
        super::OptionsIterator(self.opt_iter())
    }
}

impl<'a> MinimalWritableMessage for super::ResponseMessage<'a> {
    type Code = u8;
    type OptionNumber = u16;

    type AddOptionError = Error;
    type SetPayloadError = Error;
    type UnionError = Error;

    fn set_code(&mut self, code: Self::Code) {
        self.message.set_code_raw(code);
    }

    fn add_option(&mut self, number: Self::OptionNumber, value: &[u8]) -> Result<(), Error> {
        if self.payload_written.is_some() {
            return Err(NumericError::from_constant(riot_sys::EINVAL as _).into());
        }
        self.message.opt_add_opaque(number.into(), value)?;
        Ok(())
    }

    fn set_payload(&mut self, data: &[u8]) -> Result<(), Error> {
        self.payload_mut_with_len(data.len())?.copy_from_slice(data);
        Ok(())
    }
}

impl<'a> MutableWritableMessage for super::ResponseMessage<'a> {
    fn available_space(&self) -> usize {
        self.message.payload().len()
    }

    fn payload_mut_with_len(&mut self, len: usize) -> Result<&mut [u8], Error> {
        self.payload_written = Some(len);
        let payload = self.message.payload_mut();
        if let Some((pm, pl)) = payload.get_mut(..len + 1).and_then(<[u8]>::split_first_mut) {
            *pm = 0xff;
            Ok(pl)
        } else {
            Err(NumericError::from_constant(riot_sys::EINVAL as _).into())
        }
    }

    fn truncate(&mut self, len: usize) -> Result<(), Error> {
        if self.payload_written.is_none() {
            // payload() will not even return anything sensible yet
            return Err(NumericError::from_constant(riot_sys::EINVAL as _).into());
        }
        let pl_len = self.message.payload().len() - 1;
        if len > pl_len {
            return Err(NumericError::from_constant(riot_sys::EINVAL as _).into());
        }
        self.payload_written = Some(len);
        Ok(())
    }

    fn mutate_options<F>(&mut self, mut callback: F)
    where
        F: FnMut(Self::OptionNumber, &mut [u8]),
    {
        for (opt_num, slice) in self.message.opt_iter_mut() {
            callback(opt_num.into(), slice);
        }
    }
}