Skip to content

Commit 016f79f

Browse files
committed
replaced std::io::Error
Signed-off-by: [email protected] <[email protected]>
1 parent 337e9ab commit 016f79f

File tree

6 files changed

+214
-9
lines changed

6 files changed

+214
-9
lines changed

src/event/event.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use chrono::{DateTime, Utc};
66
use delegate_attr::delegate;
77
use std::collections::HashMap;
88
use std::fmt;
9-
use std::convert::TryFrom;
109
use std::prelude::v1::*;
1110
use url::Url;
1211

src/event/spec_version.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,12 @@ impl fmt::Display for UnknownSpecVersion {
6060
}
6161
}
6262

63-
impl no_error::Error for InvalidSpecVersion {}
63+
impl std::error::Error for UnknownSpecVersion {}
6464

6565
impl TryFrom<&str> for SpecVersion {
6666
type Error = UnknownSpecVersion;
6767

68-
fn try_from(value: &str) -> core::result::Result<Self, InvalidSpecVersion> {
68+
fn try_from(value: &str) -> core::result::Result<Self, UnknownSpecVersion> {
6969
match value {
7070
"0.3" => Ok(SpecVersion::V03),
7171
"1.0" => Ok(SpecVersion::V10),

src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@
4242
#![no_std]
4343

4444
extern crate no_std_compat as std;
45-
extern crate no_error;
46-
extern crate core_io;
4745

4846
extern crate serde;
4947
extern crate serde_json;

src/message/error.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use no_error::*;
2-
use core_io::Error;
31
use snafu::Snafu;
42
use std::prelude::v1::*;
53

@@ -34,8 +32,8 @@ pub enum Error {
3432
SerdeJsonError { source: serde_json::Error },
3533
#[snafu(display("IO Error: {}", source))]
3634
#[snafu(context(false))]
37-
IOError { source: core_io::Error },
38-
#[snafu(display("Other error: {:#?}", source))]
35+
IOError { source: super::no_std_io::Error },
36+
#[snafu(display("Other error: {:?}", source))]
3937
Other { source: Box<dyn std::error::Error> },
4038
}
4139

src/message/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
mod deserializer;
66
mod encoding;
77
mod error;
8+
mod no_std_io;
89
mod serializer;
910
mod types;
1011

12+
pub use no_std_io::{Error,Read,Write};
1113
pub use deserializer::*;
1214
pub use encoding::*;
1315
pub use error::*;

src/message/no_std_io.rs

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
//! https://docs.rs/not-io/0.1.0-alpha/not_io/
2+
//! Provides `Read` and `Write` alternatives on `no_std` while being compatible with the full
3+
//! traits from `std` when allowed.
4+
//!
5+
//! ## Motivation
6+
//!
7+
//! The file parser ecosystem of Rust is more or less split across crates that use `no_std` and
8+
//! crates that do not, as well as between crates using `alloc` and no-alloc (and the largely
9+
//! overlapping zero-copy) crates. This has several reasons:
10+
//!
11+
//! * The `std::io::Read` and `std::io::Write` traits require an allocator due to their internal
12+
//! implementation and were not written to be OS independent.
13+
//! * Before `1.36` it was not possible to depend on `alloc` without `std`.
14+
//! * The lack of specialization makes it hard to be both generic over implementors of the standard
15+
//! traits while still allowing use when those traits are not available. This is in particular
16+
//! also since several types (e.g. `&[u8]`) implement those traits but would obviously be useful
17+
//! as byte sources and sinks even when they are unavailable.
18+
//!
19+
//! ## Usage guide
20+
//!
21+
//! This crate assumes you have a structure declared roughly as follows:
22+
//!
23+
//! ```rust
24+
//! # struct SomeItem;
25+
//! # use std::io::Read;
26+
//!
27+
//! struct Decoder<T> {
28+
//! reader: T,
29+
//! }
30+
//!
31+
//! impl<T: std::io::Read> Decoder<T> {
32+
//! fn next(&mut self) -> Result<SomeItem, std::io::Error> {
33+
//! let mut buffer = vec![];
34+
//! self.reader.read_to_end(&mut buffer)?;
35+
//! # unimplemented!()
36+
//! }
37+
//! }
38+
//! ```
39+
//!
40+
//! There is only one necessary change, be sure to keep the `std` feature enabled for now. This
41+
//! should not break any code except if you relied on the precise type `T` in which case you will
42+
//! need to use a few derefs and/or `into_inner`.
43+
//!
44+
//! ```
45+
//! use not_io::AllowStd;
46+
//! # use std::io::Read;
47+
//!
48+
//! struct Decoder<T> {
49+
//! reader: AllowStd<T>,
50+
//! }
51+
//!
52+
//! # struct SomeItem;
53+
//! # impl<T: std::io::Read> Decoder<T> {
54+
//! # fn next(&mut self) -> Result<SomeItem, std::io::Error> {
55+
//! # let mut buffer = vec![];
56+
//! # self.reader.0.read_to_end(&mut buffer)?;
57+
//! # unimplemented!()
58+
//! # }
59+
//! # }
60+
//! ```
61+
//!
62+
//! And finally you can add to your crate a new default feature which enables the `std`/`alloc`
63+
//! feature of this crate, and conditionally active your existing interfaces only when that feature
64+
//! is active. Then add a few new impls that can be used even when the feature is inactive.
65+
//!
66+
//! ```
67+
//! use not_io::AllowStd;
68+
//! # struct SomeItem;
69+
//!
70+
//! struct Decoder<T> {
71+
//! reader: AllowStd<T>,
72+
//! }
73+
//!
74+
//! /// The interface which lets the caller select which feature to turn on.
75+
//! impl<T> Decoder<T>
76+
//! where
77+
//! AllowStd<T>: not_io::Read
78+
//! {
79+
//! fn no_std_next(&mut self) -> Result<SomeItem, not_io::Error> {
80+
//! # unimplemented!()
81+
//! }
82+
//! }
83+
//!
84+
//! /// An interface for pure no_std use with caller provide no_std reader.
85+
//! impl<T> Decoder<T>
86+
//! where
87+
//! T: not_io::Read
88+
//! {
89+
//! fn not_io_next(&mut self) -> Result<SomeItem, not_io::Error> {
90+
//! let reader = &mut self.reader.0;
91+
//! # unimplemented!()
92+
//! }
93+
//! }
94+
//! ```
95+
//!
96+
#![cfg_attr(not(feature = "std"), no_std)]
97+
98+
#[cfg(all(feature = "alloc", not(feature = "std")))]
99+
extern crate alloc;
100+
101+
#[derive(Debug)]
102+
pub struct Error {
103+
_private: (),
104+
}
105+
106+
pub type Result<T> = core::result::Result<T, Error>;
107+
108+
pub trait Read {
109+
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
110+
}
111+
112+
pub trait Write {
113+
fn write(&mut self, buf: &[u8]) -> Result<usize>;
114+
}
115+
116+
/// A simple new type wrapper holding a potential reader or writer.
117+
///
118+
/// This type allows the library to satisfy the compatibility across different features without
119+
/// having to resort to specialization. Simply put, this struct implements `Read` and `Write`:
120+
///
121+
/// * for all types that implement the respective trait from `std` if the `std` feature is active.
122+
/// * on a concrete subset of those types if the `alloc` feature but not the `std` feature has been
123+
/// turned on.
124+
/// * only for types from `core` when neither feature is turned on.
125+
///
126+
/// Note that without this type we couldn't safely introduce a conditionally active, generic impl
127+
/// of our own traits. The reason is that features must only activate SemVer compatible changes.
128+
/// These two sets of impls are not SemVer compatible due to the uncovered generic `T`. In
129+
/// particular in the first case you'd be allowed to implement the trait for your own type that
130+
/// also implements `std::io::Read` while in the second this is an impl conflict.
131+
///
132+
/// * `impl Read for &'_ [u8]`
133+
/// * `impl<T> Read for T where std::io::Read`
134+
///
135+
/// By adding our own private struct as a layer of indirection, you are no longer allowed to make
136+
/// such changes:
137+
///
138+
/// * `impl Read for AllowStd<&'_ [u8]>`
139+
/// * `impl<T> Read for AllowStd<T> where T: std::io::Read`
140+
///
141+
/// This still means there is one impl which will never be added. Instead, the impls for
142+
/// core/standard types are provided separately and individually.
143+
///
144+
/// * `impl<T> Read for AllowStd<T> where T: crate::Read`
145+
pub struct AllowStd<T>(pub T);
146+
147+
#[cfg(not(feature = "alloc"))]
148+
mod impls_on_neither {}
149+
150+
#[cfg(feature = "alloc")]
151+
mod impls_on_alloc {}
152+
153+
#[cfg(feature = "std")]
154+
mod impls_on_std {
155+
use super::{AllowStd, Error, Result};
156+
use std::io::{self, IoSlice, IoSliceMut};
157+
158+
impl<R: io::Read> super::Read for AllowStd<R> {
159+
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
160+
io::Read::read(&mut self.0, buf).map_err(Error::from)
161+
}
162+
}
163+
164+
impl<R: io::Read> io::Read for AllowStd<R> {
165+
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
166+
self.0.read(buf)
167+
}
168+
fn read_vectored(&mut self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
169+
self.0.read_vectored(bufs)
170+
}
171+
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
172+
self.0.read_to_end(buf)
173+
}
174+
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
175+
self.0.read_to_string(buf)
176+
}
177+
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
178+
self.0.read_exact(buf)
179+
}
180+
}
181+
182+
impl<W: io::Write> super::Write for AllowStd<W> {
183+
fn write(&mut self, buf: &[u8]) -> Result<usize> {
184+
io::Write::write(&mut self.0, buf).map_err(Error::from)
185+
}
186+
}
187+
188+
impl<W: io::Write> io::Write for AllowStd<W> {
189+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
190+
self.0.write(buf)
191+
}
192+
fn flush(&mut self) -> io::Result<()> {
193+
self.0.flush()
194+
}
195+
fn write_vectored(&mut self, bufs: &[IoSlice]) -> io::Result<usize> {
196+
self.0.write_vectored(bufs)
197+
}
198+
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
199+
self.0.write_all(buf)
200+
}
201+
}
202+
203+
impl From<io::Error> for Error {
204+
fn from(_: io::Error) -> Error {
205+
Error { _private: () }
206+
}
207+
}
208+
}

0 commit comments

Comments
 (0)