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
152
153
154
155
156
157
158
159
160
161
use crate::helpers::{block2_write_with_cf, codeconvert, Block2RequestData, Renderable};
use crate::{wkc, Code};
use coap_handler::{Handler, Reporting};
use coap_message::{MessageOption, MutableWritableMessage, ReadableMessage};
use coap_numbers::{code, option};
pub struct SimpleRenderableData(Result<Block2RequestData, Code>);
pub trait SimpleRenderable {
fn render<W: embedded_io::blocking::Write + core::fmt::Write>(&mut self, writer: &mut W);
fn content_format(&self) -> Option<u16> {
None
}
}
#[derive(Debug, Copy, Clone)]
pub struct SimpleRendered<T: SimpleRenderable>(pub T);
impl<'a> SimpleRendered<TypedStaticRenderable<'a>> {
pub fn new_typed_slice(data: &'a [u8], content_format: Option<u16>) -> Self {
SimpleRendered(TypedStaticRenderable {
data,
content_format,
})
}
pub fn new_typed_str(data: &'a str, content_format: Option<u16>) -> Self {
let data = data.as_bytes();
Self::new_typed_slice(data, content_format)
}
}
impl<T> Handler for SimpleRendered<T>
where
T: SimpleRenderable,
{
type RequestData = SimpleRenderableData;
fn extract_request_data(&mut self, request: &impl ReadableMessage) -> Self::RequestData {
let expected_accept = self.0.content_format();
let mut block2 = Ok(None);
for o in request.options() {
match o.number() {
coap_numbers::option::ACCEPT => {
if expected_accept.is_some() && o.value_uint() != expected_accept {
return SimpleRenderableData(Err(Code(coap_numbers::code::NOT_ACCEPTABLE)));
}
}
coap_numbers::option::BLOCK2 => {
block2 = match block2 {
Err(e) => Err(e),
Ok(Some(_)) => Err(Code(coap_numbers::code::BAD_REQUEST)),
Ok(None) => Block2RequestData::from_option(&o)
.map(Some)
.map_err(|_| Code(code::BAD_REQUEST)),
}
}
o if option::get_criticality(o) == option::Criticality::Critical => {
return SimpleRenderableData(Err(Code(code::BAD_OPTION)));
}
_ => (),
}
}
let reqdata = match request.code().into() {
code::GET => block2.map(|o| o.unwrap_or_default()),
_ => Err(Code(code::METHOD_NOT_ALLOWED)),
};
SimpleRenderableData(reqdata)
}
fn estimate_length(&mut self, _request: &Self::RequestData) -> usize {
1280 - 40 - 4 }
fn build_response(
&mut self,
response: &mut impl MutableWritableMessage,
request: Self::RequestData,
) {
let block2data = match request.0 {
Ok(x) => x,
Err(c) => {
c.render(response);
return;
}
};
let cf = self.0.content_format();
response.set_code(codeconvert(code::CONTENT));
block2_write_with_cf(block2data, response, |w| self.0.render(w), cf);
}
}
impl<T> Reporting for SimpleRendered<T>
where
T: SimpleRenderable,
{
type Record<'a> = wkc::EmptyRecord
where
Self: 'a,
;
type Reporter<'a> = core::iter::Once<wkc::EmptyRecord>
where
Self: 'a,
;
fn report(&self) -> Self::Reporter<'_> {
core::iter::once(wkc::EmptyRecord {})
}
}
impl<'a> SimpleRenderable for &'a str {
fn render<W>(&mut self, writer: &mut W)
where
W: core::fmt::Write,
{
writer
.write_str(self)
.expect("The backend of SimpleRenderable supports infallible writing");
}
fn content_format(&self) -> Option<u16> {
coap_numbers::content_format::from_str("text/plain; charset=utf-8")
}
}
pub struct TypedStaticRenderable<'a> {
data: &'a [u8],
content_format: Option<u16>,
}
impl<'a> SimpleRenderable for TypedStaticRenderable<'a> {
fn render<W: embedded_io::blocking::Write + core::fmt::Write>(&mut self, writer: &mut W) {
writer.write_all(self.data).unwrap();
}
fn content_format(&self) -> Option<u16> {
self.content_format
}
}