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
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);
        }
    }
}