Skip to content

Commit d6391d5

Browse files
authored
Introduce Octets trait using GATs and drop OctetsRef. (#12)
This commit changes the traits to use the generic associated types aka GATs. It drops the OctetsRef trait and all its related weirdness in favor of a simple Octets trait. This new trait serves the same purpose but is implemented by the octets sequence type itself rather than a reference to it.
1 parent 7ce668d commit d6391d5

File tree

4 files changed

+82
-126
lines changed

4 files changed

+82
-126
lines changed

.github/workflows/ci.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
strategy:
88
matrix:
99
os: [ubuntu-latest, windows-latest, macOS-latest]
10-
rust: [1.56.1, stable, beta, nightly]
10+
rust: [1.65.0, stable, beta, nightly]
1111
steps:
1212
- name: Checkout repository
1313
uses: actions/checkout@v1
@@ -25,9 +25,9 @@ jobs:
2525
# Only do this once with all features enabled.
2626
# Only do Clippy on stable for the moment, due to
2727
# clippy::unknown_clippy_lints being removed.
28-
- if: matrix.rust == 'stable'
28+
- if: matrix.rust == 'nightly'
2929
run: rustup component add clippy
30-
- if: matrix.rust == 'stable'
30+
- if: matrix.rust == 'nightyl'
3131
run: cargo clippy --all --all-features -- -D warnings
3232

3333
# Build

Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[package]
22
name = "octseq"
3-
version = "0.1.1-dev"
3+
version = "0.2.0-dev"
44
edition = "2021"
5-
rust-version = "1.56"
5+
rust-version = "1.65"
66
authors = ["Martin Hoffmann <[email protected]>"]
77
description = "Abstractions for types representing octet sequences."
88
documentation = "https://docs.rs/octseq"

src/parse.rs

+24-28
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! ref and allows to parse values from the octets.
66
77
use core::fmt;
8-
use super::traits::OctetsRef;
8+
use super::traits::Octets;
99

1010
//------------ Parser --------------------------------------------------------
1111

@@ -16,10 +16,10 @@ use super::traits::OctetsRef;
1616
/// the position beyond processed data.
1717
///
1818
/// [octets reference]: trait.OctetsRef.html
19-
#[derive(Clone, Copy, Debug)]
20-
pub struct Parser<Ref> {
19+
#[derive(Debug)]
20+
pub struct Parser<'a, Octs: ?Sized> {
2121
/// The underlying octets reference.
22-
octets: Ref,
22+
octets: &'a Octs,
2323

2424
/// The current position of the parser from the beginning of `octets`.
2525
pos: usize,
@@ -32,11 +32,11 @@ pub struct Parser<Ref> {
3232
len: usize,
3333
}
3434

35-
impl<Ref> Parser<Ref> {
35+
impl<'a, Octs: ?Sized> Parser<'a, Octs> {
3636
/// Creates a new parser atop a reference to an octet sequence.
37-
pub fn from_ref(octets: Ref) -> Self
37+
pub fn from_ref(octets: &'a Octs) -> Self
3838
where
39-
Ref: AsRef<[u8]>,
39+
Octs: Octets,
4040
{
4141
Parser {
4242
pos: 0,
@@ -46,10 +46,7 @@ impl<Ref> Parser<Ref> {
4646
}
4747

4848
/// Returns the wrapped reference to the underlying octets sequence.
49-
pub fn octets_ref(&self) -> Ref
50-
where
51-
Ref: Copy,
52-
{
49+
pub fn octets_ref(&self) -> &'a Octs {
5350
self.octets
5451
}
5552

@@ -76,7 +73,7 @@ impl<Ref> Parser<Ref> {
7673
}
7774
}
7875

79-
impl Parser<&'static [u8]> {
76+
impl Parser<'static, [u8]> {
8077
/// Creates a new parser atop a static byte slice.
8178
///
8279
/// This function is most useful for testing.
@@ -85,7 +82,7 @@ impl Parser<&'static [u8]> {
8582
}
8683
}
8784

88-
impl<Ref: AsRef<[u8]>> Parser<Ref> {
85+
impl<'a, Octs: AsRef<[u8]> + ?Sized> Parser<'a, Octs> {
8986
/// Returns an octets slice of the underlying sequence.
9087
///
9188
/// The slice covers the entire sequence, not just the remaining data. You
@@ -96,16 +93,6 @@ impl<Ref: AsRef<[u8]>> Parser<Ref> {
9693
&self.octets.as_ref()[..self.len]
9794
}
9895

99-
/// Returns a mutable octets slice of the underlying sequence.
100-
///
101-
/// The slice covers the entire sequence, not just the remaining data.
102-
pub fn as_slice_mut(&mut self) -> &mut [u8]
103-
where
104-
Ref: AsMut<[u8]>,
105-
{
106-
&mut self.octets.as_mut()[..self.len]
107-
}
108-
10996
/// Returns the number of remaining octets to parse.
11097
pub fn remaining(&self) -> usize {
11198
self.len - self.pos
@@ -167,17 +154,17 @@ impl<Ref: AsRef<[u8]>> Parser<Ref> {
167154
}
168155
}
169156

170-
impl<Ref: AsRef<[u8]>> Parser<Ref> {
157+
impl<'a, Octs: AsRef<[u8]> + ?Sized> Parser<'a, Octs> {
171158
/// Takes and returns the next `len` octets.
172159
///
173160
/// Advances the parser by `len` octets. If there aren’t enough octets
174161
/// left, leaves the parser untouched and returns an error instead.
175162
pub fn parse_octets(
176163
&mut self,
177164
len: usize,
178-
) -> Result<Ref::Range, ShortInput>
165+
) -> Result<Octs::Range<'a>, ShortInput>
179166
where
180-
Ref: OctetsRef,
167+
Octs: Octets,
181168
{
182169
let end = self.pos + len;
183170
if end > self.len {
@@ -211,8 +198,7 @@ impl<Ref: AsRef<[u8]>> Parser<Ref> {
211198
///
212199
/// If there aren’t enough octets left in the parser to fill the buffer
213200
/// completely, returns an error and leaves the parser untouched.
214-
pub fn parse_parser(&mut self, len: usize) -> Result<Self, ShortInput>
215-
where Ref: Clone {
201+
pub fn parse_parser(&mut self, len: usize) -> Result<Self, ShortInput> {
216202
self.check_len(len)?;
217203
let mut res = self.clone();
218204
res.len = res.pos + len;
@@ -337,6 +323,16 @@ impl<Ref: AsRef<[u8]>> Parser<Ref> {
337323
}
338324
}
339325

326+
impl<'a, Octs: ?Sized> Clone for Parser<'a, Octs> {
327+
fn clone(&self) -> Self {
328+
Parser {
329+
octets: self.octets,
330+
pos: self.pos,
331+
len: self.len
332+
}
333+
}
334+
}
335+
340336

341337
//--------- ShortInput -------------------------------------------------------
342338

src/traits.rs

+53-93
Original file line numberDiff line numberDiff line change
@@ -14,51 +14,16 @@
1414
//!
1515
//! # Octets
1616
//!
17-
//! There is no special trait for octets, we simply use `AsRef<[u8]>`. This
18-
//! way, any type implementing these traits can be used as a basic octets
19-
//! already. Additional properties are signalled through additional traits.
20-
//! `AsMut<[u8]>` is used to signal the ability to manipulate the contents of
21-
//! an octets sequence (while the length is still fixed). The trait
22-
//! [`Truncate`] introduced by the crate signals that an octets sequence can
23-
//! be shortened.
17+
//! In their most simple form, any type that implements `AsRef<[u8]>` can
18+
//! serve as octets. However, in some cases additional functionality is
19+
//! required.
2420
//!
25-
//! # Octets References
26-
//!
27-
//! A reference to an octets type implements [`OctetsRef`]. The main purpose
28-
//! of this trait is to allow taking a sub-sequence, called a ‘range’,
29-
//! out of the octets in the cheapest way possible. For most types, ranges
30-
//! will be octet slices `&[u8]` but some shareable types (most notably
21+
//! The trait [`Octets`] allows taking a sub-sequence, called a ‘range’, out
22+
//! of the octets in the cheapest way possible. For most types, ranges will
23+
//! be octet slices `&[u8]` but some shareable types (most notably
3124
//! `bytes::Bytes`) allow ranges to be owned values, thus avoiding the
32-
//! lifetime limitations a slice would bring.
33-
//!
34-
//! One type is special in that it is its own octets reference: `&[u8]`,
35-
//! referred to as an _octets slice_ here. This means that you
36-
//! always use an octets slice regardless of whether a type is generic over
37-
//! an octets sequence or an octets reference.
38-
//!
39-
//! The [`OctetsRef`] trait is separate because of limitations of lifetimes
40-
//! in traits. It has an associated type `OctetsRef::Range` that defines the
41-
//! type of a range. When using the trait as a trait bound for a generic type,
42-
//! you will typically use a reference to this type. For instance, a generic
43-
//! function taking part out of some octets and returning a reference to it
44-
//! could be defined like so:
45-
//!
46-
//! ```
47-
//! # use octseq::OctetsRef;
48-
//!
49-
//! fn take_part<'a, Octets>(
50-
//! src: &'a Octets
51-
//! ) -> <&'a Octets as OctetsRef>::Range
52-
//! where &'a Octets: OctetsRef {
53-
//! unimplemented!()
54-
//! }
55-
//! ```
56-
//!
57-
//! The where clause demands that whatever octets type is being used, a
58-
//! reference to it must be an octets ref. The return value refers to the
59-
//! range type defined for this octets ref. The lifetime argument is
60-
//! necessary to tie all these references together.
61-
//!
25+
//! lifetime limitations a slice would bring. Therefore, `Octets` allows
26+
//! defining the type of a range as an associated type.
6227
//!
6328
//! # Octets Builders
6429
//!
@@ -106,7 +71,7 @@
10671
//! eager you may paint yourself into a corner.
10772
//!
10873
//! In many cases you can get away with a simple `AsRef<[u8]>` bound. Only use
109-
//! an explicit `OctetsRef` bound when you need to return a range that may be
74+
//! an explicit `Octets` bound when you need to return a range that may be
11075
//! kept around.
11176
//!
11277
//! Similarly, only demand of an octets builder what you actually need. Even
@@ -124,110 +89,105 @@ use core::convert::Infallible;
12489

12590
//============ Octets and Octet Builders =====================================
12691

92+
//------------ Octets --------------------------------------------------------
12793

128-
//------------ OctetsRef -----------------------------------------------------
129-
130-
/// A reference to an octets sequence.
131-
///
132-
/// This trait is to be implemented for a (immutable) reference to a type of
133-
/// an octets sequence. I.e., it `T` is an octets sequence, `OctetsRef` needs
134-
/// to be implemented for `&T`.
94+
/// A type representing an octets sequence.
13595
///
13696
/// The primary purpose of the trait is to allow access to a sub-sequence,
13797
/// called a ‘range.’ The type of this range is given via the `Range`
138-
/// associated type. For most types it will be a `&[u8]` with a lifetime equal
139-
/// to that of the reference itself. Only if an owned range can be created
98+
/// associated type. For most types it will be a `&[u8]` with a lifetime
99+
/// equal to that of a reference. Only if an owned range can be created
140100
/// cheaply, it should be that type.
141-
///
142-
/// There is two basic ways of using the trait for a trait bound. You can
143-
/// either limit the octets sequence type itself by bounding references to it
144-
/// via a where clause. I.e., for an octets sequence type argument `Octets`
145-
/// you can specify `where &'a Octets: OctetsRef` or, if you don’t have a
146-
/// lifetime argument available `where for<'a> &'a Octets: OctetsRef`. For
147-
/// this option, you’d typically refer to values as references to the
148-
/// octets type, i.e., `&Octets`.
149-
///
150-
/// Alternatively, you can refer to the reference itself as a owned value.
151-
/// This works out fine since all octets references are required to be
152-
/// `Copy`. For instance, a function can take a value of generic type `Oref`
153-
/// and that type can then be directly bounded via `Oref: OctetsRef`.
154-
pub trait OctetsRef: AsRef<[u8]> + Copy + Sized {
155-
/// The type of a range of the sequence.
156-
type Range: AsRef<[u8]>;
101+
pub trait Octets: AsRef<[u8]> {
102+
type Range<'a>: Octets where Self: 'a;
157103

158104
/// Returns a sub-sequence or ‘range’ of the sequence.
159-
fn range(self, start: usize, end: usize) -> Self::Range;
105+
///
106+
/// # Panics
107+
///
108+
/// The method should panic if `start` or `end` are greater than the
109+
/// length of the octets sequence or if `start` is greater than `end`.
110+
fn range(&self, start: usize, end: usize) -> Self::Range<'_>;
160111

161112
/// Returns a range starting at index `start` and going to the end.
162-
fn range_from(self, start: usize) -> Self::Range {
113+
///
114+
/// # Panics
115+
///
116+
/// The method should panic if `start` is greater than the
117+
/// length of the octets sequence.
118+
fn range_from(&self, start: usize) -> Self::Range<'_> {
163119
self.range(start, self.as_ref().len())
164120
}
165121

166122
/// Returns a range from the start to before index `end`.
167-
fn range_to(self, end: usize) -> Self::Range {
123+
///
124+
/// # Panics
125+
///
126+
/// The method should panic if `end` is greater than the
127+
/// length of the octets sequence.
128+
fn range_to(&self, end: usize) -> Self::Range<'_> {
168129
self.range(0, end)
169130
}
170131

171132
/// Returns a range that covers the entire sequence.
172-
fn range_all(self) -> Self::Range {
133+
fn range_all(&self) -> Self::Range<'_> {
173134
self.range(0, self.as_ref().len())
174135
}
175136
}
176137

177-
impl<'a, T: OctetsRef> OctetsRef for &'a T {
178-
type Range = T::Range;
138+
impl<'t, T: Octets + ?Sized> Octets for &'t T {
139+
type Range<'a> = <T as Octets>::Range<'a> where Self: 'a;
179140

180-
fn range(self, start: usize, end: usize) -> Self::Range {
141+
fn range(&self, start: usize, end: usize) -> Self::Range<'_> {
181142
(*self).range(start, end)
182143
}
183144
}
184145

185-
impl<'a> OctetsRef for &'a [u8] {
186-
type Range = &'a [u8];
146+
impl Octets for [u8] {
147+
type Range<'a> = &'a [u8];
187148

188-
fn range(self, start: usize, end: usize) -> Self::Range {
149+
fn range(&self, start: usize, end: usize) -> Self::Range<'_> {
189150
&self[start..end]
190151
}
191152
}
192153

193154
#[cfg(feature = "std")]
194-
impl<'a, 's> OctetsRef for &'a Cow<'s, [u8]> {
195-
type Range = &'a [u8];
155+
impl<'c> Octets for Cow<'c, [u8]> {
156+
type Range<'a> = &'a [u8] where Self: 'a;
196157

197-
fn range(self, start: usize, end: usize) -> Self::Range {
158+
fn range(&self, start: usize, end: usize) -> Self::Range<'_> {
198159
&self.as_ref()[start..end]
199160
}
200161
}
201162

202163
#[cfg(feature = "std")]
203-
impl<'a> OctetsRef for &'a Vec<u8> {
204-
type Range = &'a [u8];
164+
impl Octets for Vec<u8> {
165+
type Range<'a> = &'a [u8];
205166

206-
fn range(self, start: usize, end: usize) -> Self::Range {
167+
fn range(&self, start: usize, end: usize) -> Self::Range<'_> {
207168
&self[start..end]
208169
}
209170
}
210171

211172
#[cfg(feature = "bytes")]
212-
impl<'a> OctetsRef for &'a Bytes {
213-
type Range = Bytes;
173+
impl Octets for Bytes {
174+
type Range<'a> = Bytes;
214175

215-
fn range(self, start: usize, end: usize) -> Self::Range {
176+
fn range(&self, start: usize, end: usize) -> Self::Range<'_> {
216177
self.slice(start..end)
217178
}
218179
}
219180

220181
#[cfg(feature = "smallvec")]
221-
impl<'a, A: smallvec::Array<Item = u8>>
222-
OctetsRef for &'a smallvec::SmallVec<A>
223-
{
224-
type Range = &'a [u8];
182+
impl<A: smallvec::Array<Item = u8>> Octets for smallvec::SmallVec<A> {
183+
type Range<'a> = &'a [u8] where A: 'a;
225184

226-
fn range(self, start: usize, end: usize) -> Self::Range {
185+
fn range(&self, start: usize, end: usize) -> Self::Range<'_> {
227186
&self.as_slice()[start..end]
228187
}
229188
}
230189

190+
231191
//------------ Truncate ------------------------------------------------------
232192

233193
/// An octet sequence that can be shortened.

0 commit comments

Comments
 (0)