From 8e07f240ccebc71668d60a82b1d4b82511cfaa89 Mon Sep 17 00:00:00 2001 From: Mark <> Date: Mon, 14 Oct 2024 00:23:14 +0200 Subject: [PATCH] allow using other stdin/stdout/stderr via RunInfo --- mers_lib/Cargo.toml | 2 +- mers_lib/src/program/configs/with_base.rs | 9 +--- mers_lib/src/program/configs/with_stdio.rs | 53 ++++++++++++++++++---- mers_lib/src/program/run/mod.rs | 33 +++++++++++++- 4 files changed, 78 insertions(+), 19 deletions(-) diff --git a/mers_lib/Cargo.toml b/mers_lib/Cargo.toml index 9ea9923..70fe203 100755 --- a/mers_lib/Cargo.toml +++ b/mers_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mers_lib" -version = "0.9.10" +version = "0.9.11" edition = "2021" license = "MIT OR Apache-2.0" description = "library to use the mers language in other projects" diff --git a/mers_lib/src/program/configs/with_base.rs b/mers_lib/src/program/configs/with_base.rs index 67373cd..8573f22 100755 --- a/mers_lib/src/program/configs/with_base.rs +++ b/mers_lib/src/program/configs/with_base.rs @@ -4,19 +4,14 @@ use std::{ }; use crate::{ - data::{ - self, - bool::bool_type, - int::{INT_MAX, INT_MIN}, - Data, MersTypeWInfo, Type, - }, + data::{self, bool::bool_type, int::INT_MAX, Data, MersTypeWInfo, Type}, errors::CheckError, program::run::{CheckInfo, Info}, }; use super::{ gen::{ - function::{func, func_end, func_err}, + function::{func, func_err}, IntR, OneOf, }, Config, diff --git a/mers_lib/src/program/configs/with_stdio.rs b/mers_lib/src/program/configs/with_stdio.rs index fb5a762..5010a75 100755 --- a/mers_lib/src/program/configs/with_stdio.rs +++ b/mers_lib/src/program/configs/with_stdio.rs @@ -1,5 +1,5 @@ use std::{ - io::Write, + io::{BufRead, Write}, sync::{Arc, Mutex}, }; @@ -66,8 +66,13 @@ impl Config { ) .add_var( "read_line", - func(|_: (), _| { - Ok(if let Some(Ok(line)) = std::io::stdin().lines().next() { + func(|_: (), i| { + let next_line = if let Some(stdin) = &mut *i.global.stdin.lock().unwrap() { + std::io::BufReader::new(stdin).lines().next() + } else { + std::io::stdin().lines().next() + }; + Ok(if let Some(Ok(line)) = next_line { OneOrNone(Some(line)) } else { OneOrNone(None) @@ -82,7 +87,15 @@ impl Config { out: Ok(Arc::new(|a, _i| Ok(a.clone()))), run: Arc::new(|a, i| { let a2 = a.get(); - eprintln!("{} :: {}", a2.as_type().with_info(i), a2.with_info(i)); + let ty = a2.as_type(); + let ty = ty.with_info(i); + let v = a2.with_info(i); + if let Some((_, stderr)) = &mut *i.global.stdout.lock().unwrap() { + let _ = write!(stderr, "{ty} :: {v}"); + let _ = stderr.flush(); + } else { + eprintln!("{ty} :: {v}"); + } drop(a2); Ok(a) }), @@ -96,8 +109,13 @@ impl Config { info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), run: Arc::new(|a, i| { - eprint!("{}", a.get().with_info(i)); - _ = std::io::stderr().lock().flush(); + if let Some((_, stderr)) = &mut *i.global.stdout.lock().unwrap() { + let _ = write!(stderr, "{}", a.get().with_info(i)); + let _ = stderr.flush(); + } else { + eprint!("{}", a.get().with_info(i)); + let _ = std::io::stderr().lock().flush(); + } Ok(Data::empty_tuple()) }), inner_statements: None, @@ -110,7 +128,12 @@ impl Config { info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), run: Arc::new(|a, i| { - eprintln!("{}", a.get().with_info(i)); + if let Some((_, stderr)) = &mut *i.global.stdout.lock().unwrap() { + let _ = writeln!(stderr, "{}", a.get().with_info(i)); + let _ = stderr.flush(); + } else { + eprintln!("{}", a.get().with_info(i)); + } Ok(Data::empty_tuple()) }), inner_statements: None, @@ -123,8 +146,13 @@ impl Config { info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), run: Arc::new(|a, i| { - print!("{}", a.get().with_info(i)); - _ = std::io::stdout().lock().flush(); + if let Some((stdout, _)) = &mut *i.global.stdout.lock().unwrap() { + let _ = write!(stdout, "{}", a.get().with_info(i)); + let _ = stdout.flush(); + } else { + print!("{}", a.get().with_info(i)); + let _ = std::io::stdout().lock().flush(); + } Ok(Data::empty_tuple()) }), inner_statements: None, @@ -137,7 +165,12 @@ impl Config { info_check: Arc::new(Mutex::new(CheckInfo::neverused())), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), run: Arc::new(|a, i| { - println!("{}", a.get().with_info(i)); + if let Some((stdout, _)) = &mut *i.global.stdout.lock().unwrap() { + let _ = writeln!(stdout, "{}", a.get().with_info(i)); + let _ = stdout.flush(); + } else { + println!("{}", a.get().with_info(i)); + } Ok(Data::empty_tuple()) }), inner_statements: None, diff --git a/mers_lib/src/program/run/mod.rs b/mers_lib/src/program/run/mod.rs index 9861209..10832c6 100755 --- a/mers_lib/src/program/run/mod.rs +++ b/mers_lib/src/program/run/mod.rs @@ -1,6 +1,7 @@ use std::{ collections::HashMap, fmt::Debug, + io::{Read, Write}, sync::{Arc, Mutex, RwLock}, time::Instant, }; @@ -126,12 +127,38 @@ pub type CheckInfo = info::Info; pub struct RunLocal { pub vars: Vec>>, } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct RunLocalGlobalInfo { /// if set, if `Instant::now()` is equal to or after the set `Instant`, stop the program with an error. pub limit_runtime: Option, pub object_fields: Arc>>, pub object_fields_rev: Arc>>, + pub stdin: Arc>>>, + pub stdout: Arc, Box)>>>, +} +#[derive(Debug)] +#[allow(unused)] +struct RunLocalGlobalInfoDebug<'a> { + pub limit_runtime: &'a Option, + pub object_fields: &'a Arc>>, + pub object_fields_rev: &'a Arc>>, + pub stdin: bool, + pub stdout: bool, +} +impl Debug for RunLocalGlobalInfo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{:?}", + RunLocalGlobalInfoDebug { + limit_runtime: &self.limit_runtime, + object_fields: &self.object_fields, + object_fields_rev: &self.object_fields_rev, + stdin: self.stdin.lock().unwrap().is_some(), + stdout: self.stdout.lock().unwrap().is_some() + } + ) + } } impl RunLocalGlobalInfo { pub fn new(object_fields: Arc>>) -> Self { @@ -139,6 +166,8 @@ impl RunLocalGlobalInfo { limit_runtime: None, object_fields, object_fields_rev: Default::default(), + stdin: Arc::new(Mutex::new(None)), + stdout: Arc::new(Mutex::new(None)), } } } @@ -216,6 +245,8 @@ impl info::Local for RunLocal { limit_runtime: None, object_fields: Default::default(), object_fields_rev: Default::default(), + stdin: Default::default(), + stdout: Default::default(), } } fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {