From a3a426835e2ae153070a937e5aba844a939eba05 Mon Sep 17 00:00:00 2001 From: Iago Bonnici <iago.bonnici@umontpellier.fr> Date: Mon, 10 Mar 2025 11:12:25 +0100 Subject: [PATCH] =?UTF-8?q?=E2=AC=87=EF=B8=8F=20Downgrade=20to=20build=20o?= =?UTF-8?q?n=20stable.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rust-toolchain.toml | 2 ++ src/from_unstable.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 13 +++++------ src/parse.rs | 2 +- src/parse/modules.rs | 6 ++--- src/parse/samples.rs | 3 ++- 6 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 rust-toolchain.toml create mode 100644 src/from_unstable.rs diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..292fe49 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" diff --git a/src/from_unstable.rs b/src/from_unstable.rs new file mode 100644 index 0000000..d1abdfb --- /dev/null +++ b/src/from_unstable.rs @@ -0,0 +1,53 @@ +//! Work around features missing from stable. + +use arrayvec::ArrayVec; + +//-------------------------------------------------------------------------------------------------- +// std::array::try_from_fn + +pub(crate) fn try_from_fn<T, E, const N: usize>( + mut f: impl FnMut(usize) -> Result<T, E>, +) -> Result<[T; N], E> { + // Use small stack-allocated vector as temporary initializer + let mut res = ArrayVec::<T, N>::new(); + for i in 0..N { + let next = f(i)?; + res.push(next); + } + Ok(res.into_inner().unwrap_or_else(|_| unreachable!())) // (to avoid T: Debug) +} + +//-------------------------------------------------------------------------------------------------- +// std::array::try_map + +pub(crate) trait TryMap<I, const N: usize>: IntoIterator<Item = I> + Sized { + fn try_map<E, O>(self, f: impl FnMut(I) -> Result<O, E>) -> Result<[O; N], E>; +} + +impl<I, const N: usize> TryMap<I, N> for [I; N] { + fn try_map<E, O>(self, f: impl FnMut(I) -> Result<O, E>) -> Result<[O; N], E> { + let mut f = f; + // Same strategy as above. + let mut res = ArrayVec::<O, N>::new(); + for a in self { + let next = f(a)?; + res.push(next); + } + Ok(res.into_inner().unwrap_or_else(|_| unreachable!())) + } +} + +//-------------------------------------------------------------------------------------------------- +// std::slice::split_once (take this opportunity to simplify for our use case) + +pub(crate) trait SplitOnce<T> { + type Chunk; + fn split_once(self, pred: T) -> Option<(Self::Chunk, Self::Chunk)>; +} +impl<'s> SplitOnce<u8> for &'s [u8] { + type Chunk = &'s [u8]; + fn split_once(self, pred: u8) -> Option<(Self::Chunk, Self::Chunk)> { + let index = self.iter().position(|&c| c == pred)?; + Some((&self[..index], &self[index + 1..])) + } +} diff --git a/src/lib.rs b/src/lib.rs index a4e359b..1280265 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,3 @@ -#![feature(array_try_from_fn)] -#![feature(array_try_map)] -#![feature(buf_read_has_data_left)] -#![feature(generic_arg_infer)] -#![feature(slice_split_once)] - use std::{ array, collections::HashMap, @@ -23,6 +17,7 @@ use colored::Colorize; pub use config::Config; use demux::Reference; use flate2::{read::MultiGzDecoder, write::GzEncoder, Compression}; +use from_unstable::{self as fun, TryMap}; use indexmap::{map::Entry, IndexMap}; use io::{Context, ContextualizedReader, ContextualizedWriter}; use num_format::{Locale, ToFormattedString}; @@ -39,6 +34,7 @@ use crate::fastq::Block; pub mod config; mod demux; mod dispatcher; +mod from_unstable; mod io; mod parse; mod reader; @@ -70,7 +66,7 @@ pub fn demultiplex(cf: &Config) -> Result<(), Error> { let in_allocs_reused = Arc::new(Mutex::new(0)); // Spawn one reader thread per input (infix) file. - let mut readers: [_; INPUT_INFIXES.len()] = array::try_from_fn(|i| -> Result<_, Error> { + let mut readers: [_; INPUT_INFIXES.len()] = fun::try_from_fn(|i| -> Result<_, Error> { let infix = INPUT_INFIXES[i]; let path = &cf.inputs[i]; println!(" {}", path.display().to_string().blue()); @@ -110,7 +106,7 @@ pub fn demultiplex(cf: &Config) -> Result<(), Error> { //---------------------------------------------------------------------------------------------- println!("Read all expected modules from references."); let [mut ref_a, mut ref_b, mut ref_c, mut ref_d] = // (mutable because of their internal caches) - array::try_from_fn(|i| -> Result<_, Error> { + fun::try_from_fn(|i| -> Result<_, Error> { let letter = MODULE_LETTERS[i]; let path = &cf.references[i]; println!(" {}", path.display().to_string().blue()); @@ -167,6 +163,7 @@ pub fn demultiplex(cf: &Config) -> Result<(), Error> { for (&code, sample_id) in &samples.map { all_writers.insert( code, + #[allow(unstable_name_collisions)] // Purposedly downgrading from nightly. OUTPUT_INFIXES.try_map(|infix| -> Result<_, Error> { // Create writer with zip | disk IO stream. let path = (cf.sample)(&ful(sample_id), infix); diff --git a/src/parse.rs b/src/parse.rs index 45ba5c2..afd9683 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,5 +1,5 @@ -pub(crate) mod modules; pub(crate) mod fastq; +pub(crate) mod modules; pub(crate) mod samples; pub(crate) use modules::parse as modules; diff --git a/src/parse/modules.rs b/src/parse/modules.rs index b3965d8..ab3074e 100644 --- a/src/parse/modules.rs +++ b/src/parse/modules.rs @@ -8,6 +8,7 @@ use snafu::{ensure, OptionExt, ResultExt, Snafu}; use crate::{ demux::Config, + from_unstable::SplitOnce, io::{self, Context}, short::ful, ContextualizedReader, @@ -59,9 +60,8 @@ fn extract_code<'l>( cf: &Config, ) -> Result<&'l [u8], ParseError> { let &Config { module_size, .. } = cf; - let (id, code) = line - .split_once(|&b| b == b'\t') - .with_context(|| LineErr { line })?; + #[allow(unstable_name_collisions)] // Purposedly downgrading from nightly. + let (id, code) = line.split_once(b'\t').with_context(|| LineErr { line })?; // Parse id and check consistency with line number. let id = id diff --git a/src/parse/samples.rs b/src/parse/samples.rs index 6fb93ae..49d01a5 100644 --- a/src/parse/samples.rs +++ b/src/parse/samples.rs @@ -11,7 +11,8 @@ use snafu::{ensure, OptionExt, ResultExt, Snafu}; use crate::{ ful, - io::{self, Context, ContextualizedReader}, MODULE_LETTERS, + io::{self, Context, ContextualizedReader}, + MODULE_LETTERS, }; #[derive(Debug)] -- GitLab