use std::{borrow::Cow, fmt};
use crate::text::Text;
#[derive(Default, Clone, Eq, PartialEq, Hash)]
pub struct Masked<'a> {
inner: Cow<'a, str>,
mask_char: char,
}
impl<'a> Masked<'a> {
pub fn new(s: impl Into<Cow<'a, str>>, mask_char: char) -> Self {
Self {
inner: s.into(),
mask_char,
}
}
pub const fn mask_char(&self) -> char {
self.mask_char
}
pub fn value(&self) -> Cow<'a, str> {
self.inner.chars().map(|_| self.mask_char).collect()
}
}
impl fmt::Debug for Masked<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.inner, f)
}
}
impl fmt::Display for Masked<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.value(), f)
}
}
impl<'a> From<&'a Masked<'a>> for Cow<'a, str> {
fn from(masked: &'a Masked) -> Self {
masked.value()
}
}
impl<'a> From<Masked<'a>> for Cow<'a, str> {
fn from(masked: Masked<'a>) -> Self {
masked.value()
}
}
impl<'a> From<&'a Masked<'_>> for Text<'a> {
fn from(masked: &'a Masked) -> Self {
Text::raw(masked.value())
}
}
impl<'a> From<Masked<'a>> for Text<'a> {
fn from(masked: Masked<'a>) -> Self {
Text::raw(masked.value())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::text::Line;
#[test]
fn new() {
let masked = Masked::new("12345", 'x');
assert_eq!(masked.inner, "12345");
assert_eq!(masked.mask_char, 'x');
}
#[test]
fn value() {
let masked = Masked::new("12345", 'x');
assert_eq!(masked.value(), "xxxxx");
}
#[test]
fn mask_char() {
let masked = Masked::new("12345", 'x');
assert_eq!(masked.mask_char(), 'x');
}
#[test]
fn debug() {
let masked = Masked::new("12345", 'x');
assert_eq!(format!("{masked:?}"), "12345");
assert_eq!(format!("{masked:.3?}"), "123", "Debug truncates");
}
#[test]
fn display() {
let masked = Masked::new("12345", 'x');
assert_eq!(format!("{masked}"), "xxxxx");
assert_eq!(format!("{masked:.3}"), "xxx", "Display truncates");
}
#[test]
fn into_text() {
let masked = Masked::new("12345", 'x');
let text: Text = (&masked).into();
assert_eq!(text.lines, [Line::from("xxxxx")]);
let text: Text = masked.into();
assert_eq!(text.lines, [Line::from("xxxxx")]);
}
#[test]
fn into_cow() {
let masked = Masked::new("12345", 'x');
let cow: Cow<str> = (&masked).into();
assert_eq!(cow, "xxxxx");
let cow: Cow<str> = masked.into();
assert_eq!(cow, "xxxxx");
}
}