Skip to content

Commit

Permalink
Minor improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
dylni committed Feb 17, 2024
1 parent 464eb9c commit a841120
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 48 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ readme = "README.md"
repository = "https://github.com/dylni/uniquote"
license = "(MIT OR Apache-2.0) AND Unicode-DFS-2016"
keywords = ["osstr", "path", "print", "quote", "unprintable"]
categories = ["command-line-interface", "no-std", "value-formatting", "wasm"]
categories = ["command-line-interface", "no-std::no-alloc", "value-formatting"]
exclude = [".*", "tests.rs", "/rustfmt.toml", "/src/bin", "/tests"]

[package.metadata.docs.rs]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ those methods are lossy; they replace all invalid characters with
[`REPLACEMENT_CHARACTER`]. This crate escapes those invalid characters instead,
allowing them to always be displayed correctly.

[![GitHub Build Status](https://github.com/dylni/uniquote/workflows/build/badge.svg?branch=master)](https://github.com/dylni/uniquote/actions?query=branch%3Amaster)
[![GitHub Build Status](https://github.com/dylni/uniquote/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/dylni/uniquote/actions/workflows/build.yml?query=branch%3Amaster)

## Usage

Expand Down
39 changes: 21 additions & 18 deletions src/escape/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ fn table_contains(table: &[(u32, u32)], code_point: CodePoint) -> bool {
let code_point = code_point.into();
table
.binary_search_by_key(&code_point, |&(x, _)| x)
.err()
.map(|index| {
.map(|_| true)
.unwrap_or_else(|index| {
index
.checked_sub(1)
.map(|x| code_point <= table[x].1)
.unwrap_or(false)
})
.unwrap_or(true)
}

fn is_printable(ch: char) -> bool {
Expand All @@ -37,23 +36,18 @@ fn is_printable(ch: char) -> bool {

enum EscapedCodePoint {
Hex(CodePoint),
Literal(char),
Literal { ch: char, escape: bool },
Quote(),
Repeated(char),
Sequence(&'static str),
}

impl EscapedCodePoint {
fn format(self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Literal(ch) => return f.write_char(ch),
Self::Repeated(ch) => {
for _ in 0..2 {
f.write_char(ch)?;
}
return Ok(());
if let Self::Literal { ch, escape } = self {
for _ in 0..=(escape.into()) {
f.write_char(ch)?;
}
_ => {}
return Ok(());
}

f.write_char(START_ESCAPE)?;
Expand Down Expand Up @@ -90,9 +84,15 @@ impl From<char> for EscapedCodePoint {
'\r' => Self::Sequence("r"),

QUOTE => Self::Quote(),
END_ESCAPE | START_ESCAPE => Self::Repeated(value),

_ if is_printable(value) => Self::Literal(value),
END_ESCAPE | START_ESCAPE => Self::Literal {
ch: value,
escape: true,
},

_ if is_printable(value) => Self::Literal {
ch: value,
escape: false,
},
_ => Self::Hex(value.into()),
}
}
Expand Down Expand Up @@ -140,7 +140,10 @@ impl Escape for str {
}

let code_point = ch.into();
escaped = !matches!(code_point, EscapedCodePoint::Literal(_));
escaped = !matches!(
code_point,
EscapedCodePoint::Literal { escape: false, .. },
);
if escaped {
push_literal!(i);
code_point.format(f)?;
Expand Down Expand Up @@ -182,7 +185,7 @@ impl Escape for [u8] {
}
}

pub(super) fn escape_utf16<I>(iter: I, f: &mut Formatter<'_>) -> fmt::Result
pub(super) fn utf16<I>(iter: I, f: &mut Formatter<'_>) -> fmt::Result
where
I: IntoIterator<Item = u16>,
{
Expand Down
8 changes: 1 addition & 7 deletions src/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,6 @@ pub type Result = result::Result<(), Error>;
/// uniformly. However, it is usually sufficient to pass this struct to the
/// [`Quote::escape`] implementation of another type.
///
/// # Safety
///
/// Although this type is annotated with `#[repr(transparent)]`, the inner
/// representation is not stable. Transmuting between this type and any other
/// causes immediate undefined behavior.
///
/// [`Quote::escape`]: super::Quote::escape
#[repr(transparent)]
pub struct Formatter<'a>(pub(super) fmt::Formatter<'a>);
Expand All @@ -61,7 +55,7 @@ impl<'a> Formatter<'a> {
where
I: IntoIterator<Item = u16>,
{
escape::escape_utf16(iter, &mut self.0).map_err(Error)
escape::utf16(iter, &mut self.0).map_err(Error)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
//! # #[cfg(feature = "std")]
//! # {
//! impl Display for FileNotFoundError {
//! fn fmt(&self, f: &mut Formatter) -> fmt::Result {
//! fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
//! write!(f, "file not found at {}", self.0.quote())
//! }
//! }
Expand Down
16 changes: 8 additions & 8 deletions src/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,16 @@ pub trait Quote {

macro_rules! r#impl {
( $($type:ty),+ ) => {
$(
impl Quote for $type {
#[inline]
fn escape(&self, f: &mut Formatter<'_>) -> $crate::Result {
use super::escape::Escape;
$(
impl Quote for $type {
#[inline]
fn escape(&self, f: &mut Formatter<'_>) -> $crate::Result {
use super::escape::Escape;

Escape::escape(self, &mut f.0).map_err(Error)
}
Escape::escape(self, &mut f.0).map_err(Error)
}
)+
}
)+
};
}
r#impl!(char, str, [u8]);
Expand Down
24 changes: 12 additions & 12 deletions tests/integration.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::char;
use std::char::REPLACEMENT_CHARACTER;
use std::fmt::Display;

use uniquote::Quote;
Expand Down Expand Up @@ -63,30 +63,30 @@ fn test_chinese() {

#[test]
fn test_replacement_character() {
test_unchanged(&char::REPLACEMENT_CHARACTER);
test_unchanged(&REPLACEMENT_CHARACTER);
}

#[cfg(feature = "std")]
#[test]
fn test_os_string() {
#[cfg(windows)]
#[cfg(unix)]
{
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;

test(
r#""fo{~ud800}o""#,
OsString::from_wide(&[0x66, 0x6F, 0xD800, 0x6F]).quote(),
r#""fo{~u80}o""#,
OsStr::from_bytes(b"\x66\x6F\x80\x6F").quote(),
);
}
#[cfg(not(windows))]
#[cfg(windows)]
{
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;

test(
r#""fo{~u80}o""#,
OsStr::from_bytes(&[0x66, 0x6F, 0x80, 0x6F]).quote(),
r#""fo{~ud800}o""#,
OsString::from_wide(&[0x66, 0x6F, 0xD800, 0x6F]).quote(),
);
}
}

0 comments on commit a841120

Please sign in to comment.