Skip to content

Commit 1ea2440

Browse files
authored
fix: use autocfg to detect rustc version (#7)
* feat: autocfg * ci: general improvement remove targets, add toolchains, introduce cargo-hack * feat: bump to 0.2.1
1 parent 68aacc4 commit 1ea2440

File tree

4 files changed

+85
-13
lines changed

4 files changed

+85
-13
lines changed

.github/workflows/ci.yml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,29 @@ jobs:
88
strategy:
99
fail-fast: false
1010
matrix:
11-
rust-toolchain: [nightly]
12-
targets: [x86_64-unknown-linux-gnu, x86_64-unknown-none, riscv64gc-unknown-none-elf, aarch64-unknown-none-softfloat]
11+
rust-toolchain:
12+
- nightly
13+
- nightly-2025-05-20
14+
- nightly-2025-12-12
15+
- stable
16+
env:
17+
RUSTC_BOOTSTRAP: "${{ matrix.rust-toolchain == 'stable' && '1' || '' }}"
1318
steps:
1419
- uses: actions/checkout@v4
1520
- uses: dtolnay/rust-toolchain@nightly
1621
with:
1722
toolchain: ${{ matrix.rust-toolchain }}
1823
components: rust-src, clippy, rustfmt
19-
targets: ${{ matrix.targets }}
2024
- name: Check rust version
2125
run: rustc --version --verbose
2226
- name: Check code format
23-
run: cargo fmt --all -- --check
27+
run: cargo fmt --all --check
28+
29+
- uses: taiki-e/install-action@cargo-hack
2430
- name: Clippy
25-
run: cargo clippy --target ${{ matrix.targets }} --all-features -- -A clippy::new_without_default
26-
- name: Build
27-
run: cargo build --target ${{ matrix.targets }} --all-features
31+
run: cargo hack clippy --feature-powerset
2832
- name: Unit test
29-
if: ${{ matrix.targets == 'x86_64-unknown-linux-gnu' }}
30-
run: cargo test --target ${{ matrix.targets }} -- --nocapture
33+
run: cargo hack test --feature-powerset -- --nocapture
3134

3235
doc:
3336
runs-on: ubuntu-latest

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "axio"
3-
version = "0.2.0"
3+
version = "0.2.1"
44
edition = "2021"
55
authors = ["Yuekai Jia <equation618@gmail.com>"]
66
description = "`std::io`-like I/O traits for `no_std` environment"
@@ -17,3 +17,6 @@ default = []
1717

1818
[dependencies]
1919
axerrno = "0.1"
20+
21+
[build-dependencies]
22+
autocfg = "1"

build.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
fn main() {
2+
autocfg::emit_possibility("borrowedbuf_init");
3+
autocfg::rerun_path("build.rs");
4+
5+
let ac = autocfg::new();
6+
let code = r#"
7+
#![no_std]
8+
#![feature(core_io_borrowed_buf)]
9+
pub fn probe() {
10+
let _ = core::io::BorrowedBuf::init_len;
11+
}
12+
"#;
13+
if ac.probe_raw(code).is_ok() {
14+
autocfg::emit("borrowedbuf_init");
15+
}
16+
}

src/lib.rs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![cfg_attr(not(doc), no_std)]
44
#![feature(doc_cfg)]
55
#![feature(core_io_borrowed_buf)]
6+
#![cfg_attr(not(borrowedbuf_init), feature(maybe_uninit_fill))]
67

78
#[cfg(feature = "alloc")]
89
extern crate alloc;
@@ -67,6 +68,11 @@ pub fn default_read_to_end<R: Read + ?Sized>(
6768
}
6869
}
6970

71+
#[cfg(borrowedbuf_init)]
72+
let mut initialized = 0; // Extra initialized bytes from previous loop iteration
73+
#[cfg(borrowedbuf_init)]
74+
let mut consecutive_short_reads = 0;
75+
7076
loop {
7177
if buf.len() == buf.capacity() && buf.capacity() == start_cap {
7278
// The buffer might be an exact fit. Let's read into a probe buffer
@@ -92,15 +98,35 @@ pub fn default_read_to_end<R: Read + ?Sized>(
9298
spare = &mut spare[..buf_len];
9399
let mut read_buf: BorrowedBuf<'_> = spare.into();
94100

101+
#[cfg(borrowedbuf_init)]
102+
// SAFETY: These bytes were initialized but not filled in the previous loop
103+
unsafe {
104+
read_buf.set_init(initialized);
105+
}
106+
95107
let mut cursor = read_buf.unfilled();
96108
// Difference from `std`: We don't have a `read_buf` method that returns both data and an error, so we return early on error.
97-
let n = r.read(unsafe { cursor.as_mut().assume_init_mut() })?;
98-
assert!(n <= cursor.capacity());
99-
unsafe {
109+
#[cfg(borrowedbuf_init)]
110+
{
111+
let n = r.read(cursor.ensure_init().init_mut())?;
100112
cursor.advance(n);
101113
}
114+
#[cfg(not(borrowedbuf_init))]
115+
{
116+
// SAFETY: We do not uninitialize any part of the buffer.
117+
let n = r.read(unsafe { cursor.as_mut().write_filled(0) })?;
118+
assert!(n <= cursor.capacity());
119+
// SAFETY: We've initialized the entire buffer, and `read` can't make it uninitialized.
120+
unsafe {
121+
cursor.advance(n);
122+
}
123+
}
102124

125+
#[cfg(borrowedbuf_init)]
126+
let unfilled_but_initialized = cursor.init_mut().len();
103127
let bytes_read = cursor.written();
128+
#[cfg(borrowedbuf_init)]
129+
let was_fully_initialized = read_buf.init_len() == buf_len;
104130

105131
// SAFETY: BorrowedBuf's invariants mean this much memory is initialized.
106132
unsafe {
@@ -112,8 +138,32 @@ pub fn default_read_to_end<R: Read + ?Sized>(
112138
return Ok(buf.len() - start_len);
113139
}
114140

141+
#[cfg(borrowedbuf_init)]
142+
if bytes_read < buf_len {
143+
consecutive_short_reads += 1;
144+
} else {
145+
consecutive_short_reads = 0;
146+
}
147+
148+
#[cfg(borrowedbuf_init)]
149+
{
150+
// store how much was initialized but not filled
151+
initialized = unfilled_but_initialized;
152+
}
153+
115154
// Use heuristics to determine the max read size if no initial size hint was provided
116155
if size_hint.is_none() {
156+
#[cfg(borrowedbuf_init)]
157+
// The reader is returning short reads but it doesn't call ensure_init().
158+
// In that case we no longer need to restrict read sizes to avoid
159+
// initialization costs.
160+
// When reading from disk we usually don't get any short reads except at EOF.
161+
// So we wait for at least 2 short reads before uncapping the read buffer;
162+
// this helps with the Windows issue.
163+
if !was_fully_initialized && consecutive_short_reads > 1 {
164+
max_read_size = usize::MAX;
165+
}
166+
117167
// we have passed a larger buffer than previously and the
118168
// reader still hasn't returned a short read
119169
if buf_len >= max_read_size && bytes_read == buf_len {

0 commit comments

Comments
 (0)