aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2024-06-23 17:07:22 -0700
committeriximeow <me@iximeow.net>2024-06-23 17:07:22 -0700
commit1fb5a7903bb44d44e298959d2637d858b2ea8e38 (patch)
tree15ae7bb8f58eba0966b28448f563276c3df70455
parenta8ec2d655ca59d7118ca1ea47dada705183b5442 (diff)
document new AnsiDisplaySink, add more -arch tests for sinks
-rw-r--r--src/color_new.rs63
-rw-r--r--src/display/display_sink.rs4
-rw-r--r--src/testkit.rs4
-rw-r--r--src/testkit/display.rs12
-rw-r--r--tests/display.rs72
5 files changed, 129 insertions, 26 deletions
diff --git a/src/color_new.rs b/src/color_new.rs
index 482a624..ae941f2 100644
--- a/src/color_new.rs
+++ b/src/color_new.rs
@@ -42,7 +42,57 @@ pub trait YaxColors {
fn function(&self) -> Color;
}
-mod ansi {
+/// support for colorizing text with ANSI control sequences.
+///
+/// the most useful item in this module is [`AnsiDisplaySink`], which interprets span entry and
+/// exit as points at which ANSI sequences may need to be written into the output it wraps - that
+/// output may be any type implementing [`DisplaySink`], including [`FmtSink`] to adapt any
+/// implementer of `fmt::Write` such as standard out.
+///
+/// ## example
+///
+/// to write colored text to standard out:
+///
+/// ```
+/// # #[cfg(feature="alloc")]
+/// # {
+/// # extern crate alloc;
+/// # use alloc::string::String;
+/// use yaxpeax_arch::color_new::DefaultColors;
+/// use yaxpeax_arch::color_new::ansi::AnsiDisplaySink;
+/// use yaxpeax_arch::display::FmtSink;
+///
+/// let mut s = String::new();
+/// let mut s_sink = FmtSink::new(&mut s);
+///
+/// let mut writer = AnsiDisplaySink::new(&mut s_sink, DefaultColors);
+///
+/// // this might be a yaxpeax crate's `display_into`, or other library implementation code
+/// mod fake_yaxpeax_crate {
+/// use yaxpeax_arch::display::DisplaySink;
+///
+/// pub fn format_memory_operand<T: DisplaySink>(out: &mut T) -> core::fmt::Result {
+/// out.span_start_immediate();
+/// out.write_prefixed_u8(0x80)?;
+/// out.span_end_immediate();
+/// out.write_fixed_size("(")?;
+/// out.span_start_register();
+/// out.write_fixed_size("rbp")?;
+/// out.span_end_register();
+/// out.write_fixed_size(")")?;
+/// Ok(())
+/// }
+/// }
+///
+/// // this might be how a user uses `AnsiDisplaySink`, which will write ANSI-ful text to `s` and
+/// // print it.
+///
+/// fake_yaxpeax_crate::format_memory_operand(&mut writer).expect("write succeeds");
+///
+/// println!("{}", s);
+/// # }
+/// ```
+pub mod ansi {
use crate::color_new::Color;
// color sequences as described by ECMA-48 and, apparently, `man 4 console_codes`
@@ -97,17 +147,26 @@ mod ansi {
/// type, so the only available error mechanism would be to also `abort()`.
///
/// if this turns out to be a bad decision, it'll have to be rethought!
- struct AnsiDisplaySink<'sink, T: DisplaySink, Y: YaxColors> {
+ pub struct AnsiDisplaySink<'sink, T: DisplaySink, Y: YaxColors> {
out: &'sink mut T,
span_stack: alloc::vec::Vec<Color>,
colors: Y
}
impl<'sink, T: DisplaySink, Y: YaxColors> AnsiDisplaySink<'sink, T, Y> {
+ pub fn new(out: &'sink mut T, colors: Y) -> Self {
+ Self {
+ out,
+ span_stack: alloc::vec::Vec::new(),
+ colors,
+ }
+ }
+
fn push_color(&mut self, color: Color) {
self.span_stack.push(color);
let _ = self.out.write_fixed_size(super::color2ansi(color));
}
+
fn restore_prev_color(&mut self) {
let _ = self.span_stack.pop();
if let Some(prev_color) = self.span_stack.last() {
diff --git a/src/display/display_sink.rs b/src/display/display_sink.rs
index 18713cd..9bad1e3 100644
--- a/src/display/display_sink.rs
+++ b/src/display/display_sink.rs
@@ -350,6 +350,10 @@ impl<'a, T: fmt::Write> FmtSink<'a, T> {
pub fn new(f: &'a mut T) -> Self {
Self { out: f }
}
+
+ pub fn inner_ref(&self) -> &T {
+ &self.out
+ }
}
/// blanket impl that discards all span information, forwards writes to the underlying `fmt::Write`
diff --git a/src/testkit.rs b/src/testkit.rs
index 6600d80..996b1e4 100644
--- a/src/testkit.rs
+++ b/src/testkit.rs
@@ -5,4 +5,6 @@
//! [`yaxpeax_arch::display::DisplaySink`], but may grow in the future.
#[cfg(feature="alloc")]
-pub mod display;
+mod display;
+#[cfg(feature="alloc")]
+pub use display::{DisplaySinkValidator, DisplaySinkWriteComparator};
diff --git a/src/testkit/display.rs b/src/testkit/display.rs
index 3cffd49..3cef59c 100644
--- a/src/testkit/display.rs
+++ b/src/testkit/display.rs
@@ -147,6 +147,18 @@ pub struct DisplaySinkWriteComparator<'sinks, T: DisplaySink, U: DisplaySink> {
}
impl<'sinks, T: DisplaySink, U: DisplaySink> DisplaySinkWriteComparator<'sinks, T, U> {
+ pub fn new(
+ t: &'sinks mut T, t_check: fn(&T) -> &str,
+ u: &'sinks mut U, u_check: fn(&U) -> &str
+ ) -> Self {
+ Self {
+ sink1: t,
+ sink1_check: t_check,
+ sink2: u,
+ sink2_check: u_check,
+ }
+ }
+
fn compare_sinks(&self) {
let sink1_text = (self.sink1_check)(self.sink1);
let sink2_text = (self.sink2_check)(self.sink2);
diff --git a/tests/display.rs b/tests/display.rs
index 887db53..a6d6eb1 100644
--- a/tests/display.rs
+++ b/tests/display.rs
@@ -1,27 +1,5 @@
-/*
-#[test]
-fn sinks_are_equivalent() {
- use yaxpeax_arch::display::NoColorsSink;
- use yaxpeax_arch::testkit::DisplaySinkWriteComparator;
-
- let mut bare = String::new();
- let mut through_sink = String::new();
- for i in 0..u64::MAX {
- bare.clear();
- through_sink.clear();
- let mut out = NoColorsSink {
- out: &mut through_sink
- };
- let mut comparator = DisplaySinkWriteComparator {
- sink1: &mut out,
- sink1_check: |sink| { sink.out.as_str() },
- sink2: &mut bare,
- sink2_check: |sink| { sink.as_str() },
- };
- }
-}
-*/
+// this was something of a misfeature for these formatters..
#[test]
#[allow(deprecated)]
fn formatters_are_not_feature_gated() {
@@ -86,3 +64,51 @@ fn display_sink_write_hex_helpers() {
assert_eq!(buf, expected);
}
}
+
+#[cfg(feature="alloc")]
+#[test]
+fn sinks_are_equivalent() {
+ use yaxpeax_arch::display::{DisplaySink, FmtSink};
+ use yaxpeax_arch::testkit::DisplaySinkWriteComparator;
+
+ let mut bare = String::new();
+ let mut through_sink = String::new();
+ for i in 0..u16::MAX {
+ bare.clear();
+ through_sink.clear();
+ let mut out = FmtSink::new(&mut through_sink);
+ let mut comparator = DisplaySinkWriteComparator::new(
+ &mut out,
+ |sink| { sink.inner_ref().as_str() },
+ &mut bare,
+ |sink| { sink.as_str() },
+ );
+ comparator.write_u16(i).expect("write succeeds");
+ comparator.write_prefixed_u16(i).expect("write succeeds");
+ comparator.write_prefixed_i16(i as i16).expect("write succeeds");
+ }
+}
+
+#[cfg(all(feature="alloc", feature="color-new"))]
+#[test]
+fn ansi_sink_works() {
+ use yaxpeax_arch::color_new::ansi::AnsiDisplaySink;
+ use yaxpeax_arch::display::DisplaySink;
+
+ let mut buf = String::new();
+
+ let mut ansi_sink = AnsiDisplaySink::new(&mut buf, yaxpeax_arch::color_new::DefaultColors);
+
+ ansi_sink.span_start_immediate();
+ ansi_sink.write_prefixed_u8(0x80).expect("write succeeds");
+ ansi_sink.span_end_immediate();
+ ansi_sink.write_fixed_size("(").expect("write succeeds");
+ ansi_sink.span_start_register();
+ ansi_sink.write_fixed_size("rbp").expect("write succeeds");
+ ansi_sink.span_end_register();
+ ansi_sink.write_fixed_size(")").expect("write succeeds");
+
+ drop(ansi_sink);
+
+ assert_eq!(buf, "\x1b[37m0x80\x1b[39m(\x1b[38;5;6mrbp\x1b[39m)");
+}