data_streams/
lib.rs

1// Copyright 2024 - Strixpyrr
2// SPDX-License-Identifier: Apache-2.0
3
4//! This crate provides stream traits for conveniently read and writing many data types: bytes,
5//! little or big-endian integers, and UTF-8 strings. [`DataSource`] reads from a stream, [`DataSink`]
6//! writes to a stream.
7//!
8//! Implementations for byte slices and `std::io`'s buffered readers and writers are provided, but
9//! it's easy to write your own implementations:
10//!
11//! ```no_run
12//! # use data_streams::{DataSource, DataSink, Result};
13//!
14//! struct MySource {
15//!     buffer: Vec<u8>,
16//!     // ...
17//! }
18//!
19//! impl DataSource for MySource {
20//!     fn available(&self) -> usize {
21//!         self.buffer.len()
22//!     }
23//!
24//!     fn request(&mut self, count: usize) -> Result<bool> {
25//!         if self.available() < count {
26//!             // Fill the buffer...
27//!         }
28//!
29//!         Ok(self.available() >= count)
30//!     }
31//!
32//!     fn skip(&mut self, count: usize) -> Result<usize> {
33//!         // Read bytes up to count bytes from the stream...
34//!         // Here we just consume from the buffer as an example.
35//!         self.buffer.drain(..count);
36//!         Ok(count)
37//!     }
38//!
39//!     fn read_bytes<'a>(&mut self, buf: &'a mut [u8]) -> Result<&'a [u8]> {
40//!         let count = self.available().min(buf.len());
41//!         buf[..count].copy_from_slice(&self.buffer);
42//!         self.buffer.drain(..count);
43//!         Ok(&buf[..count])
44//!     }
45//! }
46//!
47//! struct MySink {
48//!     buffer: Vec<u8>,
49//!     // ...
50//! }
51//!
52//! impl DataSink for MySink {
53//!     fn write_bytes(&mut self, buf: &[u8]) -> Result {
54//!         self.buffer.extend_from_slice(buf);
55//!         // Flush the buffer?
56//!         Ok(())
57//!     }
58//! }
59//! ```
60//! 
61//! # Feature flags
62//! 
63//! - `std`: Provides impls for [`std::io`] types, such as [`BufReader`](std::io::BufReader) and
64//!   [`BufWriter`](std::io::BufWriter). Requires a dependency on the Rust standard library. Disable
65//!   to allow usage with `no_std`.
66//! - `alloc`: Provides impls for dynamically allocated types such as [`Vec`], and source methods
67//!   for reading into these. Requires a heap allocator, which may not be present on platforms
68//!   without the standard library.
69//! - `utf8`: Enables reading UTF-8-validated data from sources, and writing to [`String`]s, using a
70//!   very fast SIMD validation algorithm from the [`simdutf8`](https://github.com/rusticstuff/simdutf8)
71//!   crate. UTF-8 can be written to sinks without this feature.
72//! - `unstable`: Provides unstable features only present on the nightly compiler. Enables:
73//!   - `unstable_borrowed_buf`: Provides [`DataSource`] impls for [`BorrowedBuf`](core::io::BorrowedBuf)
74//!     and [`BorrowedCursor`](core::io::BorrowedCursor).
75//!   - `unstable_specialization`: Enables trait specialization, providing a default [`DataSource`]
76//!     for impls of [`BufferAccess`].
77//!   - `unstable_uninit_slice`: Provides a [`DataSink`] impl for `&mut [MaybeUninit<u8>]`.
78
79#![cfg_attr(not(feature = "std"), no_std)]
80#![cfg_attr(feature = "unstable_ascii_char", feature(ascii_char))]
81#![cfg_attr(feature = "unstable_specialization", feature(specialization))]
82#![cfg_attr(feature = "unstable_borrowed_buf", feature(core_io_borrowed_buf))]
83#![cfg_attr(feature = "unstable_uninit_slice", feature(maybe_uninit_write_slice))]
84#![cfg_attr(test, feature(assert_matches))]
85#![allow(incomplete_features)]
86
87#![deny(
88	clippy::alloc_instead_of_core,
89	clippy::as_pointer_underscore,
90	clippy::as_underscore,
91	clippy::assertions_on_result_states,
92	clippy::cfg_not_test,
93	clippy::clone_on_ref_ptr,
94	clippy::decimal_literal_representation,
95	clippy::deref_by_slicing,
96	clippy::else_if_without_else,
97	clippy::empty_drop,
98	clippy::empty_enum_variants_with_brackets,
99	clippy::empty_structs_with_brackets,
100	clippy::exhaustive_enums,
101	clippy::field_scoped_visibility_modifiers,
102	clippy::if_then_some_else_none,
103	clippy::impl_trait_in_params,
104	clippy::infinite_loop,
105	clippy::map_err_ignore,
106	clippy::mem_forget,
107	clippy::missing_assert_message,
108	clippy::missing_errors_doc,
109	clippy::missing_panics_doc,
110	clippy::missing_safety_doc,
111	clippy::multiple_unsafe_ops_per_block,
112	clippy::panic,
113	clippy::partial_pub_fields,
114	clippy::redundant_type_annotations,
115	clippy::ref_patterns,
116	clippy::renamed_function_params,
117	clippy::semicolon_inside_block,
118	clippy::std_instead_of_alloc,
119	clippy::std_instead_of_core,
120	clippy::undocumented_unsafe_blocks,
121	clippy::unwrap_used,
122)]
123
124#[cfg(feature = "alloc")]
125extern crate alloc;
126extern crate core;
127
128mod error;
129mod source;
130mod sink;
131mod slice;
132mod vec;
133mod core_io;
134mod std_io;
135mod utf8;
136mod wrappers;
137
138pub mod markers {
139	pub mod source {
140		pub use crate::source::markers::{InfiniteSource, SourceSize};
141	}
142}
143
144pub use error::Error;
145#[cfg(feature = "unstable_ascii_char")]
146pub use error::AsciiError;
147#[cfg(feature = "utf8")]
148pub use error::{Utf8Error, Utf8ErrorKind, SimdUtf8Error};
149pub use sink::{DataSink, GenericDataSink};
150#[cfg(feature = "alloc")]
151pub use sink::VecSink;
152pub use source::{BufferAccess, DataSource, GenericDataSource};
153#[cfg(feature = "alloc")]
154pub use source::VecSource;
155
156pub type Result<T = (), E = Error> = core::result::Result<T, E>;