Skip to content

Commit

Permalink
Refactor show! macro; update trait bound about writting; update tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
TheVeryDarkness committed Sep 3, 2024
1 parent 51c9a35 commit 4bf54d0
Show file tree
Hide file tree
Showing 15 changed files with 175 additions and 79 deletions.
20 changes: 20 additions & 0 deletions examples/doc_fn_read.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use iof::read;

/// Some examples of reading from standard input using the `read` function.
fn main() {
// Read a single integer from input.
let n: u32 = read();
assert_eq!(n, 42);

// Read a string from input.
let s: String = read();
assert_eq!(s, "Hello!");

// Read an array of integers from input.
let arr: [u32; 4] = read();
assert_eq!(arr, [1, 2, 3, 4]);

// Read a nested array of integers from input.
let arr: [[u32; 2]; 2] = read();
assert_eq!(arr, [[1, 2], [3, 4]]);
}
5 changes: 5 additions & 0 deletions examples/doc_fn_read.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
42
Hello!
1 2 3 4
1 2
3 4
6 changes: 6 additions & 0 deletions examples/doc_show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@ fn main() {

// Write a tuple to output.
show!((1, 2, 3));

// Write a tuple of tuples to output.
show!(((1, 2), (3, 4)));

// Write an empty tuple to output.
show!(());
}
2 changes: 2 additions & 0 deletions examples/doc_show.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ Hello, World!
.@/
#$$
1 2 3
1 2 3 4

26 changes: 3 additions & 23 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,33 +209,13 @@
//! Given the input below:
//!
//! ```txt
//! 42
//! Hello, World!
//! 1 2 3 4
//! 1 2
//! 3 4
#![doc = include_str!("../examples/doc_fn_read.txt")]
//! ```
//!
//! Code below reads the input and stores it in variables:
//!
//! ```rust,no_run
//! use iof::read;
//!
//! // Read a single integer from input.
//! let n: u32 = read();
//! assert_eq!(n, 42);
//!
//! // Read a string from input.
//! let s: String = read();
//! assert_eq!(s, "Hello, World!");
//!
//! // Read an array of integers from input.
//! let arr: [u32; 4] = read();
//! assert_eq!(arr, [1, 2, 3, 4]);
//!
//! // Read a nested array of integers from input.
//! let arr: [[u32; 2]; 2] = read();
//! assert_eq!(arr, [[1, 2], [3, 4]]);
#![doc = include_str!("../examples/doc_fn_read.rs")]
//! ```
//!
//! # Output
Expand Down Expand Up @@ -333,7 +313,7 @@ pub use {
},
stdio::{read_into::*, stdin, stdout, stream::*},
stream::{input_stream::InputStream, traits::BufReadExt},
write::{WriteInto, WriteOneInto},
write::{writer::Writer, WriteInto, WriteOneInto},
};

mod array;
Expand Down
2 changes: 1 addition & 1 deletion src/sep_by.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl_for_sep_by!(LowerExp);
impl_for_sep_by!(UpperExp);

impl<I: Iterator<Item = T> + Clone, T: WriteInto> WriteInto for SepBy<'_, I> {
fn try_write_into<S: Write>(&self, s: &mut S) -> Result<(), io::Error> {
fn try_write_into<S: Write + ?Sized>(&self, s: &mut S) -> Result<(), io::Error> {
let mut iter = self.iter.clone();
if let Some(first) = iter.next() {
first.try_write_into(s)?;
Expand Down
6 changes: 3 additions & 3 deletions src/write/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl_write_into!(
impl WriteOneInto for char {
const SEP_ITEM: &'static str = "";

fn try_write_one_into<S: io::Write>(&self, s: &mut S) -> io::Result<()> {
fn try_write_one_into<S: io::Write + ?Sized>(&self, s: &mut S) -> io::Result<()> {
s.write_all(&[*self as u8])
}
}
Expand All @@ -31,7 +31,7 @@ macro_rules! impl_write_one_into_for_tuple {
impl<$t0: WriteOneInto, $($t: WriteOneInto),*> WriteOneInto for ($t0, $($t,)*) {
const SEP_ITEM: &'static str = " ";

fn try_write_one_into<S: io::Write>(&self, s: &mut S) -> io::Result<()> {
fn try_write_one_into<S: io::Write + ?Sized>(&self, s: &mut S) -> io::Result<()> {
let ($n0, $($n, )*) = self;
$n0.try_write_one_into(s)?;
$(
Expand All @@ -46,7 +46,7 @@ macro_rules! impl_write_one_into_for_tuple {
impl WriteOneInto for () {
const SEP_ITEM: &'static str = " ";

fn try_write_one_into<S: io::Write>(&self, _s: &mut S) -> io::Result<()> {
fn try_write_one_into<S: io::Write + ?Sized>(&self, _s: &mut S) -> io::Result<()> {
Ok(())
}
}
Expand Down
57 changes: 18 additions & 39 deletions src/write/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,46 +14,25 @@
/// [WriteInto]: crate::WriteInto
#[macro_export(local_inner_macros)]
macro_rules! show {
(; end=$end:expr, sep=$sep:expr) => {
$crate::WriteInto::write(&$end);
};
($expr:expr $(, $res:expr)*; end=$end:expr, sep=$sep:expr) => {
$crate::WriteInto::write(&$expr);
$(
$crate::WriteInto::write(&$sep);
$crate::WriteInto::write(&$res);
)*
$crate::WriteInto::write(&$end);
};
($expr:expr $(, $res:expr)*; sep=$sep:expr, end=$end:expr) => {
$crate::show!($expr $(, $res)*; end=$end, sep=$sep);
};
($expr:expr $(, $res:expr)*; end=$end:expr) => {
$crate::show!($expr $(, $res)*; end=$end, sep=" ");
};
($expr:expr $(, $res:expr)*; sep=$sep:expr) => {
$crate::show!($expr $(, $res)*; end="\n", sep=$sep);
};
($expr:expr $(, $res:expr)* $(;)?) => {
$crate::show!($expr $(, $res)*; end="\n", sep="");
};

(; end=$end:expr) => {
$crate::WriteInto::write(&$end);
};
(; sep=$sep:expr, end=$end:expr) => {
$crate::show!(; end=$end, sep=$sep);
};
(; end=$end:expr) => {
$crate::show!(; end=$end, sep=" ");
};
(; sep=$sep:expr) => {
$crate::show!(; end="\n", sep=$sep);
};
($(;)?) => {
$crate::show!(; end="\n", sep="");
($($expr:expr),* $(,)? ; $($opt:ident=$val:expr),* $(,)?) => {
unwrap!(|| -> ::std::io::Result<()> {
$crate::Writer::new()
$(.$opt($val))*
$(.write(&$expr)?)*
.finish()?;
Ok(())
}())
};
($($expr:expr),* $(,)?) => {
unwrap!(|| -> ::std::io::Result<()> {
$crate::Writer::new()
$(.write(&$expr)?)*
.finish()?;
Ok(())
}())
};
}

/// Implement [WriteInto] for given types that already implements [std::fmt::Display].
///
/// [WriteInto]: crate::WriteInto
Expand All @@ -62,7 +41,7 @@ macro_rules! impl_write_into {
($($ty:ty)*) => {
$(
impl $crate::WriteOneInto for $ty {
fn try_write_one_into<S: ::std::io::Write>(&self, s: &mut S) -> ::std::io::Result<()> {
fn try_write_one_into<S: ::std::io::Write + ?::std::marker::Sized>(&self, s: &mut S) -> ::std::io::Result<()> {
::std::write!(s, "{}", self)
}
}
Expand Down
23 changes: 12 additions & 11 deletions src/write/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::io::{self, Write};

mod impls;
mod macros;
pub(super) mod writer;

type Result<T = ()> = io::Result<T>;

Expand All @@ -17,15 +18,15 @@ pub trait WriteOneInto {
/// Separator between lines.
const SEP_LINE: &'static str = "\n";
/// Write into a stream.
fn try_write_one_into<S: Write>(&self, s: &mut S) -> Result;
fn try_write_one_into<S: Write + ?Sized>(&self, s: &mut S) -> Result;
/// Unwrapping version of [WriteOneInto::try_write_one_into].
fn write_one_into<S: Write>(&self, s: &mut S) {
fn write_one_into<S: Write + ?Sized>(&self, s: &mut S) {
unwrap!(self.try_write_one_into(s))
}
}

impl<T: WriteOneInto + ?Sized> WriteOneInto for &T {
fn try_write_one_into<S: Write>(&self, s: &mut S) -> Result {
fn try_write_one_into<S: Write + ?Sized>(&self, s: &mut S) -> Result {
(*self).try_write_one_into(s)
}
}
Expand All @@ -41,9 +42,9 @@ impl<T: WriteOneInto + ?Sized> WriteOneInto for &T {
/// [Mat]: crate::Mat
pub trait WriteInto {
/// Write into a stream.
fn try_write_into<S: Write>(&self, s: &mut S) -> Result;
fn try_write_into<S: Write + ?Sized>(&self, s: &mut S) -> Result;
/// Unwrapping version of [WriteInto::try_write_into].
fn write_into<S: Write>(&self, s: &mut S) {
fn write_into<S: Write + ?Sized>(&self, s: &mut S) {
unwrap!(self.try_write_into(s))
}
/// Write into a string.
Expand All @@ -68,30 +69,30 @@ pub trait WriteInto {
}

impl<T: WriteOneInto> WriteInto for T {
fn try_write_into<S: Write>(&self, s: &mut S) -> Result<()> {
fn try_write_into<S: Write + ?Sized>(&self, s: &mut S) -> Result<()> {
self.try_write_one_into(s)
}
}

impl<T: WriteOneInto> WriteInto for Vec<T> {
fn try_write_into<S: Write>(&self, s: &mut S) -> Result<()> {
fn try_write_into<S: Write + ?Sized>(&self, s: &mut S) -> Result<()> {
self.as_slice().try_write_into(s)
}
}

impl<T: WriteOneInto, const N: usize> WriteInto for [T; N] {
fn try_write_into<S: Write>(&self, s: &mut S) -> Result<()> {
fn try_write_into<S: Write + ?Sized>(&self, s: &mut S) -> Result<()> {
self.as_slice().try_write_into(s)
}
}
impl<T: WriteOneInto> WriteInto for [T] {
fn try_write_into<S: Write>(&self, s: &mut S) -> Result<()> {
fn try_write_into<S: Write + ?Sized>(&self, s: &mut S) -> Result<()> {
WriteInto::try_write_into(&self.sep_by(T::SEP_ITEM), s)
}
}

impl<T: WriteOneInto> WriteInto for Mat<T> {
fn try_write_into<S: Write>(&self, s: &mut S) -> Result<()> {
fn try_write_into<S: Write + ?Sized>(&self, s: &mut S) -> Result<()> {
self.iter()
.map(|row| row.iter().sep_by(T::SEP_ITEM))
.sep_by(T::SEP_LINE)
Expand All @@ -100,7 +101,7 @@ impl<T: WriteOneInto> WriteInto for Mat<T> {
}

impl<T: WriteOneInto, const M: usize, const N: usize> WriteInto for [[T; N]; M] {
fn try_write_into<S: Write>(&self, s: &mut S) -> Result<()> {
fn try_write_into<S: Write + ?Sized>(&self, s: &mut S) -> Result<()> {
self.iter()
.map(|row| row.iter().sep_by(T::SEP_ITEM))
.sep_by(T::SEP_LINE)
Expand Down
70 changes: 70 additions & 0 deletions src/write/writer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use super::WriteInto;
use crate::stdout;
use std::io::{self, Write};

/// Configuration for the writer.
pub struct Writer<'sep, 'end, 'buf> {
index: usize,
sep: &'sep str,
end: &'end str,
buf: Option<&'buf mut dyn Write>,
}

impl<'sep, 'end, 'buf> Writer<'sep, 'end, 'buf> {
/// Create a new writer.
pub fn new() -> Self {
let sep = " ";
let end = "\n";
let buf = None;
Self {
index: 0,
sep,
end,
buf,
}
}
/// Set the separator.
pub fn sep(&mut self, sep: &'sep str) -> &mut Self {
self.sep = sep;
self
}
/// Set the end.
pub fn end(&mut self, end: &'end str) -> &mut Self {
self.end = end;
self
}
/// Set the buffer.
pub fn buf(&mut self, buf: &'buf mut impl Write) -> &mut Self {
self.buf = Some(buf);
self
}
/// Write a value.
pub fn write<V: WriteInto>(&mut self, value: &V) -> io::Result<&mut Self> {
match self.buf.as_mut() {
Some(buf) => {
if self.index > 0 {
self.sep.try_write_into(buf)?;
}
value.try_write_into(buf)?;
}
None => {
let buf = &mut stdout();
if self.index > 0 {
self.sep.try_write_into(buf)?;
}
value.try_write_into(buf)?;
}
}
self.index += 1;
Ok(self)
}
/// Finish writing.
pub fn finish(&mut self) -> io::Result<()> {
if let Some(buf) = self.buf.as_mut() {
self.end.try_write_into(buf)
} else {
let buf = &mut stdout();
self.end.try_write_into(buf)
}
}
}
2 changes: 1 addition & 1 deletion tests/ill_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::io::{Result, Write};
struct IllData(&'static [u8]);

impl WriteInto for IllData {
fn try_write_into<S: Write>(&self, s: &mut S) -> Result<()> {
fn try_write_into<S: Write + ?Sized>(&self, s: &mut S) -> Result<()> {
s.write_all(self.0)?;
Ok(())
}
Expand Down
9 changes: 8 additions & 1 deletion tests/string.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use iof::{InputStream, ReadFrom, ReadInto, ReadOneFrom, ReadOneInto};
use iof::{show, InputStream, ReadFrom, ReadInto, ReadOneFrom, ReadOneInto};
use std::io::Cursor;

#[test]
Expand Down Expand Up @@ -144,3 +144,10 @@ fn read_in_line_some_unicode() {

assert!(<String>::try_read_in_line_some_trimmed_from(&mut reader).is_err());
}

#[test]
fn string() {
let mut buf = Cursor::new(Vec::new());
show!("Hello, World!"; end = "", buf = &mut buf);
show!("🦀🦀🦀"; buf = &mut buf);
}
10 changes: 10 additions & 0 deletions tests/test_bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ fn doc_read() {
test_example("doc_read", include_str!("../examples/doc_read.txt"), "");
}

#[test]
#[cfg_attr(miri, ignore)]
fn doc_fn_read() {
test_example(
"doc_fn_read",
include_str!("../examples/doc_fn_read.txt"),
"",
);
}

#[test]
#[cfg_attr(miri, ignore)]
fn doc_get_line() {
Expand Down
Loading

0 comments on commit 4bf54d0

Please sign in to comment.