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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
//! Traits and tools to implement a .well-known/core resource easily
//!
//! This tries to be future-proof for building also CoRAL responses, without going out of its way
//! for that.
//!
//! The [Reporting] trait is a bit of mis-fit for coap_handler_implementations, and should not be
//! too tightly coupled with the remainign components. It is a candidate for moving in with
//! coap-handler or a to-be created coap-discovery crate (when it and its components have matured),
//! while NotReporting etc. would stay here.

use coap_handler::Handler;
use coap_message::{MutableWritableMessage, ReadableMessage};

/// A property an advertised resource can have many of.
///
/// This corresponds to target attributes in Link Format.
#[non_exhaustive]
pub enum Attribute {
    Observable,
    Interface(&'static str),
    ResourceType(&'static str),
    Title(&'static str),
    Ct(u16), // Single only -- array could be added in an own option
    Sz(usize),
}

/// A entry produced by Reporting, corresponding to a single link in a Link Format file.
pub trait Record<'a> {
    type PathElements: Iterator<Item = &'a &'a str>;
    type Attributes: Iterator<Item = &'a Attribute>;

    /// List of path segments (equivalent to Uri-Path option values) leading to the indicated
    /// resoruce
    fn path(&self) -> Self::PathElements;

    /// Link relation (or None to default to the implicit "hosts")
    ///
    /// Note that the allowed character set is limited compared to full UTF-8 strings.
    fn rel(&self) -> Option<&'a str>;

    /// Target attributes of the link
    fn attributes(&self) -> Self::Attributes;
}

/// Indicates that this resource can produce output for a .well-known/core resource.
pub trait Reporting {
    type Record<'a>: Record<'a>
    where
        Self: 'a;
    type Reporter<'a>: Iterator<Item = Self::Record<'a>>
    where
        Self: 'a;

    fn report(&self) -> Self::Reporter<'_>;
}

/// Wrapper around arbitrary Handlers to make them not report in .well-known/core.
///
/// This helps integrating handler implementations that do not yet also implement Reporting by
/// providing a blank report.
///
/// (With specialization, this could be moved into the default implementation).
pub struct NotReporting<H: Handler>(H);

impl<H: Handler> NotReporting<H> {
    pub fn new(handler: H) -> Self {
        NotReporting(handler)
    }
}

// Is DerefMut appropriate? Would be less code...
impl<H: Handler> Handler for NotReporting<H> {
    type RequestData = H::RequestData;
    fn extract_request_data(&mut self, m: &impl ReadableMessage) -> H::RequestData {
        self.0.extract_request_data(m)
    }
    fn estimate_length(&mut self, r: &Self::RequestData) -> usize {
        self.0.estimate_length(r)
    }
    fn build_response(&mut self, m: &mut impl MutableWritableMessage, r: Self::RequestData) {
        self.0.build_response(m, r)
    }
}

/// A report with no path, relation or attributes
///
/// This is convenient both in places where a type is needed as an element for an Empty iterator
/// (as in NotReporting) and to wrap a resource with no further properties in (in a Once iterator,
/// relying on the tree builder to augment the empty path with the actual path).
pub struct EmptyRecord;

impl<'a> Record<'a> for EmptyRecord {
    type PathElements = core::iter::Empty<&'a &'a str>;
    type Attributes = core::iter::Empty<&'a Attribute>;

    fn path(&self) -> Self::PathElements {
        core::iter::empty()
    }
    fn rel(&self) -> Option<&'static str> {
        None
    }
    fn attributes(&self) -> Self::Attributes {
        core::iter::empty()
    }
}

impl<H: Handler> Reporting for NotReporting<H> {
    type Record<'a>
    where
        Self: 'a,
    = EmptyRecord;
    type Reporter<'a>
    where
        Self: 'a,
    = core::iter::Empty<EmptyRecord>;

    fn report(&self) -> Self::Reporter<'_> {
        core::iter::empty()
    }
}

/// Wrapper around arbitrary Handlers to make them report some attributes. The path is often
/// configured empty, relying on the tree builder to augment it with the actual path.
///
/// This helps integrating handler implementations that do not manually implement Reporting.
///
/// Any Reporting the handler might implement is overridden by this.
pub struct ConstantSingleRecordReport<'a, H: Handler> {
    handler: H,
    path: &'a [&'a str],
    attributes: &'a [Attribute],
}

impl<'a, H: Handler> ConstantSingleRecordReport<'a, H> {
    /// Wrap a handler with attributes reported at its single path
    pub fn new(handler: H, attributes: &'a [Attribute]) -> Self {
        ConstantSingleRecordReport {
            handler,
            path: &[],
            attributes,
        }
    }

    /// Wrap a handler with attributes and additional path components
    ///
    /// Compared to [`.new()`](ConstantSingleRecordReport::new), this is primarily useful for
    /// handlers that *do* perform own path processing (and are thus instanciated `.below()` some
    /// path), but whose root resource is not the resource below which is put. This is a typical
    /// case: To use relative references, it is convenient to make a handler go
    /// `.below(&["path"])`, but then expect an extra `/` segment (an empty component in the path
    /// list) at the end -- and then deal out relative references like `1` or `./2` to go to
    /// `/path/2`. Such handlers put `&[""]` in the path argument.
    pub fn new_with_path(handler: H, attributes: &'a [Attribute], path: &'a [&'a str]) -> Self {
        ConstantSingleRecordReport {
            handler,
            path,
            attributes,
        }
    }
}

// Is DerefMut appropriate? Would be less code...
impl<'a, H: Handler> Handler for ConstantSingleRecordReport<'a, H> {
    type RequestData = H::RequestData;
    fn extract_request_data(&mut self, m: &impl ReadableMessage) -> H::RequestData {
        self.handler.extract_request_data(m)
    }
    fn estimate_length(&mut self, r: &Self::RequestData) -> usize {
        self.handler.estimate_length(r)
    }
    fn build_response(&mut self, m: &mut impl MutableWritableMessage, r: Self::RequestData) {
        self.handler.build_response(m, r)
    }
}

pub struct ConstantSliceRecord<'a> {
    path: &'a [&'a str],
    attributes: &'a [Attribute],
}

impl<'a> Record<'a> for ConstantSliceRecord<'a> {
    type PathElements = core::slice::Iter<'a, &'a str>;
    type Attributes = core::slice::Iter<'a, Attribute>;

    fn path(&self) -> Self::PathElements {
        self.path.iter()
    }
    fn rel(&self) -> Option<&'static str> {
        None
    }
    fn attributes(&self) -> Self::Attributes {
        self.attributes.iter()
    }
}

impl<'a, H: Handler> Reporting for ConstantSingleRecordReport<'a, H> {
    type Record<'b>
    where
        Self: 'b,
    = ConstantSliceRecord<'b>;
    type Reporter<'b>
    where
        Self: 'b,
    = core::iter::Once<ConstantSliceRecord<'b>>;

    fn report(&self) -> Self::Reporter<'_> {
        core::iter::once(ConstantSliceRecord {
            path: self.path,
            attributes: self.attributes,
        })
    }
}