From 348c5029b350fa2f00378bd4a9031f64737ef883 Mon Sep 17 00:00:00 2001 From: Skgland Date: Mon, 18 Aug 2025 20:52:15 +0200 Subject: [PATCH] reduce msrv back to 1.85 --- Cargo.lock | 1 + Cargo.toml | 9 +- build/main.rs | 4 + src/arena.rs | 4 +- src/machine/streams.rs | 9 +- src/machine/streams/compat.rs | 70 +++++++++++++++ src/machine/system_calls.rs | 157 +++++++++++++++++++++++++--------- 7 files changed, 207 insertions(+), 47 deletions(-) create mode 100644 src/machine/streams/compat.rs diff --git a/Cargo.lock b/Cargo.lock index c00125e0..8069db30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2777,6 +2777,7 @@ dependencies = [ "to-syn-value_derive", "tokio", "trycmd", + "version_check", "walkdir", "warp", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 6406a832..faa2ee89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["prolog", "prolog-interpreter", "prolog-system"] categories = ["command-line-utilities"] build = "build/main.rs" # Remember to check CI -rust-version = "1.87" +rust-version = "1.85" [lib] crate-type = ["cdylib", "rlib"] @@ -25,6 +25,12 @@ tls = ["dep:native-tls"] http = ["dep:warp", "dep:reqwest"] crypto-full = [] +[lints.rust] +unexpected_cfgs = { level = "deny", check-cfg = [ + 'cfg(rust_version, values("1.87.0"))', +] } + + [build-dependencies] indexmap = "2.3.0" proc-macro2 = "1.0.86" @@ -34,6 +40,7 @@ strum_macros = "0.26" syn = { version = "2.0.72", features = ['full', 'visit', 'extra-traits'] } to-syn-value = "0.1.1" to-syn-value_derive = "0.1.1" +version_check = "0.9.5" walkdir = "2" [dependencies] diff --git a/build/main.rs b/build/main.rs index 66bcbfcc..9212bfe9 100644 --- a/build/main.rs +++ b/build/main.rs @@ -43,6 +43,10 @@ fn find_prolog_files(path_prefix: &str, current_dir: &Path) -> Vec<(String, Path } fn main() { + if version_check::is_min_version("1.87.0").unwrap_or(false) { + println!(r#"cargo:rustc-cfg=rust_version="1.87.0""#); + } + let has_rustfmt = Command::new("rustfmt") .arg("--version") .stdin(Stdio::inherit()) diff --git a/src/arena.rs b/src/arena.rs index ee9dda20..11db7581 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -14,8 +14,6 @@ use ordered_float::OrderedFloat; use std::fmt; use std::fmt::Debug; use std::hash::{Hash, Hasher}; -use std::io::PipeReader; -use std::io::PipeWriter; use std::mem; use std::mem::ManuallyDrop; use std::net::TcpListener; @@ -25,6 +23,8 @@ use std::ptr; use std::ptr::addr_of_mut; use std::ptr::NonNull; +use crate::machine::streams::{PipeReader, PipeWriter}; + macro_rules! arena_alloc { ($e:expr, $arena:expr) => {{ let result = $e; diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 596b09de..c0f5c7b3 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -23,8 +23,6 @@ use std::fmt::Debug; use std::fs::{File, OpenOptions}; use std::hash::Hash; use std::io; -use std::io::PipeReader; -use std::io::PipeWriter; use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; use std::mem::ManuallyDrop; use std::net::{Shutdown, TcpStream}; @@ -40,6 +38,9 @@ use native_tls::TlsStream; #[cfg(feature = "http")] use warp::hyper; +mod compat; +pub use compat::*; + #[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)] #[bits = 1] pub enum StreamType { @@ -1413,14 +1414,14 @@ impl Stream { )) } - pub(crate) fn from_pipe_writer(writer: io::PipeWriter, arena: &mut Arena) -> Stream { + pub(crate) fn from_pipe_writer(writer: PipeWriter, arena: &mut Arena) -> Stream { Stream::PipeWriter(arena_alloc!( ManuallyDrop::new(StreamLayout::new(CharReader::new(writer))), arena )) } - pub(crate) fn from_pipe_reader(reader: io::PipeReader, arena: &mut Arena) -> Stream { + pub(crate) fn from_pipe_reader(reader: PipeReader, arena: &mut Arena) -> Stream { Stream::PipeReader(arena_alloc!( ManuallyDrop::new(StreamLayout::new(CharReader::new(reader))), arena diff --git a/src/machine/streams/compat.rs b/src/machine/streams/compat.rs new file mode 100644 index 00000000..bb040ca5 --- /dev/null +++ b/src/machine/streams/compat.rs @@ -0,0 +1,70 @@ +#[cfg(rust_version = "1.87.0")] +pub use ge_1_87_0::{PipeReader, PipeWriter}; + +#[cfg(not(rust_version = "1.87.0"))] +pub use lt_1_87_0::{PipeReader, PipeWriter}; + +#[cfg(not(rust_version = "1.87.0"))] +pub(crate) use lt_1_87_0::PipeReaderInner; + +#[cfg(not(rust_version = "1.87.0"))] +mod lt_1_87_0 { + use std::process::{ChildStderr, ChildStdout}; + + pub type PipeWriter = std::process::ChildStdin; + + #[derive(Debug)] + pub struct PipeReader(pub(crate) PipeReaderInner); + + #[derive(Debug)] + pub(crate) enum PipeReaderInner { + Stdout(ChildStdout), + Stderr(ChildStderr), + } + + impl std::io::Read for PipeReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + match &mut self.0 { + PipeReaderInner::Stdout(child_stdout) => child_stdout.read(buf), + PipeReaderInner::Stderr(child_stderr) => child_stderr.read(buf), + } + } + + fn read_vectored( + &mut self, + bufs: &mut [std::io::IoSliceMut<'_>], + ) -> std::io::Result { + match &mut self.0 { + PipeReaderInner::Stdout(child_stdout) => child_stdout.read_vectored(bufs), + PipeReaderInner::Stderr(child_stderr) => child_stderr.read_vectored(bufs), + } + } + + fn read_to_end(&mut self, buf: &mut Vec) -> std::io::Result { + match &mut self.0 { + PipeReaderInner::Stdout(child_stdout) => child_stdout.read_to_end(buf), + PipeReaderInner::Stderr(child_stderr) => child_stderr.read_to_end(buf), + } + } + + fn read_to_string(&mut self, buf: &mut String) -> std::io::Result { + match &mut self.0 { + PipeReaderInner::Stdout(child_stdout) => child_stdout.read_to_string(buf), + PipeReaderInner::Stderr(child_stderr) => child_stderr.read_to_string(buf), + } + } + + fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> { + match &mut self.0 { + PipeReaderInner::Stdout(child_stdout) => child_stdout.read_exact(buf), + PipeReaderInner::Stderr(child_stderr) => child_stderr.read_exact(buf), + } + } + } +} + +#[cfg(rust_version = "1.87.0")] +mod ge_1_87_0 { + pub type PipeReader = std::io::PipeReader; + pub type PipeWriter = std::io::PipeWriter; +} diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index b5c850de..60a4a515 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8446,13 +8446,13 @@ impl Machine { .collect::>(); let stdin_args = self.machine_st.try_from_list(stdin_r, stub_gen)?; - let stdin = self.handle_input_stream(stdin_args)?; + let stdin = self.handle_input_stream(&stdin_args)?; let stdout_args = self.machine_st.try_from_list(stdout_r, stub_gen)?; - let stdout = self.handle_output_stream(stdout_args)?; + let stdout = self.handle_output_stream(&stdout_args)?; let stderr_args = self.machine_st.try_from_list(stderr_r, stub_gen)?; - let stderr = self.handle_output_stream(stderr_args)?; + let stderr = self.handle_output_stream(&stderr_args)?; let env_args = self.machine_st.try_from_list(env_r, stub_gen)?; @@ -8507,7 +8507,13 @@ impl Machine { .stderr(stderr); match command.spawn() { - Ok(child) => { + #[cfg_attr(rust_version = "1.87.0", expect(unused_mut))] + Ok(mut child) => { + #[cfg(not(rust_version = "1.87.0"))] + { + self.anon_pipe_compat(&mut child, &stdin_args, &stdout_args, &stderr_args)?; + } + let child_process_alloc: TypedArenaPtr = arena_alloc!(child, &mut self.machine_st.arena); @@ -8530,32 +8536,94 @@ impl Machine { } } - fn handle_output_stream(&mut self, args: Vec) -> Result { + #[cfg(not(rust_version = "1.87.0"))] + fn anon_pipe_compat( + &mut self, + child: &mut std::process::Child, + stdin_args: &[HeapCellValue], + stdout_args: &[HeapCellValue], + stderr_args: &[HeapCellValue], + ) -> CallResult { + if let Some(atom!("pipe")) = stdin_args[0].to_atom() { + let writer = child.stdin.take().expect("Should have captured stdin"); + + let stream = Stream::from_pipe_writer(writer, &mut self.machine_st.arena); + + self.indices + .add_stream(stream, atom!("process_create"), 3) + .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; + + unify!(self.machine_st, stdin_args[1], HeapCellValue::from(stream)); + } + + if let Some(atom!("pipe")) = stdout_args[0].to_atom() { + let writer = child.stdout.take().expect("Should have captured stdout"); + + let stream = Stream::from_pipe_reader( + PipeReader(PipeReaderInner::Stdout(writer)), + &mut self.machine_st.arena, + ); + + self.indices + .add_stream(stream, atom!("process_create"), 3) + .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; + + unify!(self.machine_st, stdout_args[1], HeapCellValue::from(stream)); + } + + if let Some(atom!("pipe")) = stderr_args[0].to_atom() { + let writer = child.stderr.take().expect("Should have captured stderr"); + + let stream = Stream::from_pipe_reader( + PipeReader(PipeReaderInner::Stderr(writer)), + &mut self.machine_st.arena, + ); + + self.indices + .add_stream(stream, atom!("process_create"), 3) + .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; + + unify!(self.machine_st, stderr_args[1], HeapCellValue::from(stream)); + } + + Ok(()) + } + + fn handle_output_stream(&mut self, args: &[HeapCellValue]) -> Result { Ok(match args[0].to_atom() { Some(atom!("std")) => Stdio::inherit(), Some(atom!("null")) => Stdio::null(), Some(atom!("pipe")) => { - let (reader, writer) = match std::io::pipe() { - Ok(pipe_pair) => pipe_pair, - Err(_) => { - return Err(self.machine_st.open_permission_error( - atom!("anonymous_pipe"), - atom!("process_create"), - 3, - )); - } - }; + #[cfg(rust_version = "1.87.0")] + #[allow(clippy::incompatible_msrv)] + { + let (reader, writer) = match std::io::pipe() { + Ok(pipe_pair) => pipe_pair, + Err(_) => { + return Err(self.machine_st.open_permission_error( + atom!("anonymous_pipe"), + atom!("process_create"), + 3, + )); + } + }; - let stream = Stream::from_pipe_reader(reader, &mut self.machine_st.arena); + let stream = Stream::from_pipe_reader(reader, &mut self.machine_st.arena); - self.indices - .add_stream(stream, atom!("process_create"), 3) - .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; + self.indices + .add_stream(stream, atom!("process_create"), 3) + .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; - self.machine_st - .bind(args[1].as_var().unwrap(), stream.into()); + self.machine_st + .bind(args[1].as_var().unwrap(), stream.into()); + + Stdio::from(writer) + } - Stdio::from(writer) + #[cfg(not(rust_version = "1.87.0"))] + { + Stdio::piped() + } } Some(atom!("file")) => { let path = self.machine_st.value_to_str_like(args[1]).unwrap(); @@ -8578,32 +8646,41 @@ impl Machine { }) } - fn handle_input_stream(&mut self, args: Vec) -> Result { + fn handle_input_stream(&mut self, args: &[HeapCellValue]) -> Result { Ok(match args[0].to_atom() { Some(atom!("std")) => Stdio::inherit(), Some(atom!("null")) => Stdio::null(), Some(atom!("pipe")) => { - let (reader, writer) = match std::io::pipe() { - Ok(pipe_pair) => pipe_pair, - Err(_) => { - return Err(self.machine_st.open_permission_error( - atom!("anonymous_pipe"), - atom!("process_create"), - 3, - )); - } - }; + #[cfg(rust_version = "1.87.0")] + #[allow(clippy::incompatible_msrv)] + { + let (reader, writer) = match std::io::pipe() { + Ok(pipe_pair) => pipe_pair, + Err(_) => { + return Err(self.machine_st.open_permission_error( + atom!("anonymous_pipe"), + atom!("process_create"), + 3, + )); + } + }; - let stream = Stream::from_pipe_writer(writer, &mut self.machine_st.arena); + let stream = Stream::from_pipe_writer(writer, &mut self.machine_st.arena); - self.indices - .add_stream(stream, atom!("process_create"), 3) - .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; + self.indices + .add_stream(stream, atom!("process_create"), 3) + .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; - self.machine_st - .bind(args[1].as_var().unwrap(), stream.into()); + self.machine_st + .bind(args[1].as_var().unwrap(), stream.into()); - Stdio::from(reader) + Stdio::from(reader) + } + + #[cfg(not(rust_version = "1.87.0"))] + { + Stdio::piped() + } } Some(atom!("file")) => { let path = self.machine_st.value_to_str_like(args[1]).unwrap(); -- 2.54.0