120 lines
3.8 KiB
Rust
120 lines
3.8 KiB
Rust
use std::io::Write;
|
|
|
|
/// The parser/transformator. Given a `token` and a `suffix`, adds the `suffix`
|
|
/// after the `token` to any byte buffer given to [`Parser::process`].
|
|
///
|
|
/// For example, with a `Parser::new(b"foo", b"bar"), calling
|
|
/// `parser.process(b"is foo a bar?", &mut writer)` will result in
|
|
/// `"is foobar a bar?"` being written to `writer`.
|
|
//
|
|
// NOTE: Feel free to modify this struct as needed.
|
|
pub struct Parser {
|
|
token: &'static [u8],
|
|
suffix: &'static [u8],
|
|
}
|
|
|
|
impl Parser {
|
|
/// Create a new `Parser` which will append `suffix` after `token` whenever
|
|
/// it appears in input passed to `process`.
|
|
//
|
|
// NOTE: This function signature should stay the same.
|
|
pub fn new(token: &'static [u8], suffix: &'static [u8]) -> Self {
|
|
Self { token, suffix }
|
|
}
|
|
|
|
/// Write the bytes given in `input` to `output`, plus the bytes in `suffix`
|
|
/// immediately after `token`, including across call boundaries.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// If the token is present in the input, the writer gets the input plus
|
|
/// the suffix right after the token. For instance, here,
|
|
/// `does this foo go bar?` is transformed into
|
|
/// `does this foobar go bar?`.
|
|
///
|
|
/// ```rust
|
|
/// # use code_challenge::Parser;
|
|
/// let mut parser = Parser::new(b"foo", b"bar");
|
|
/// let mut buffer = Vec::new();
|
|
/// parser.process(b"does this foo go bar?", &mut buffer).unwrap();
|
|
/// assert_eq!(b"does this foobar go bar?", buffer.as_slice());
|
|
/// ```
|
|
///
|
|
/// This works even if the token is split across multiple calls to the
|
|
/// `process` method on the same instance of `Parser`.
|
|
/// For instance, this is exactly the same as the previous example,
|
|
/// but splits the input across multiple calls to `parser`.
|
|
///
|
|
/// ```rust
|
|
/// # use code_challenge::Parser;
|
|
/// let mut parser = Parser::new(b"foo", b"bar");
|
|
/// let mut buffer = Vec::new();
|
|
/// parser.process(b"does this f", &mut buffer).unwrap();
|
|
/// parser.process(b"oo go bar?", &mut buffer).unwrap();
|
|
/// assert_eq!(b"does this foobar go bar?", buffer.as_slice());
|
|
/// ```
|
|
//
|
|
// NOTE: This function signature should stay the same.
|
|
pub fn process(&mut self, input: &[u8], output: &mut dyn Write) -> Result<(), std::io::Error> {
|
|
output.write_all(input)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_output_unmodified() {
|
|
let mut parser = Parser::new(b"lalala", b"");
|
|
let mut buffer = Vec::new();
|
|
parser
|
|
.process(b"does not contain the token", &mut buffer)
|
|
.expect("couldn't write to buffer");
|
|
assert_eq!(
|
|
"does not contain the token",
|
|
String::from_utf8_lossy(&buffer)
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn test_output_onetoken() {
|
|
let mut parser = Parser::new(b"token", b"xxx");
|
|
let mut buffer = Vec::new();
|
|
parser
|
|
.process(b"does contain the token", &mut buffer)
|
|
.expect("couldn't write to buffer");
|
|
assert_eq!(
|
|
"does contain the tokenxxx",
|
|
String::from_utf8_lossy(&buffer)
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn test_output_onetoken_multi() {
|
|
let mut parser = Parser::new(b"token", b"xxx");
|
|
let mut buffer = Vec::new();
|
|
parser
|
|
.process(b"does contain ", &mut buffer)
|
|
.expect("couldn't write to buffer");
|
|
parser
|
|
.process(b"the tok", &mut buffer)
|
|
.expect("couldn't write to buffer");
|
|
parser
|
|
.process(b"en", &mut buffer)
|
|
.expect("couldn't write to buffer");
|
|
assert_eq!(
|
|
"does contain the tokenxxx",
|
|
String::from_utf8_lossy(&buffer)
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn test_output_splittoken() {
|
|
let mut parser = Parser::new(b"token", b"xxx");
|
|
let mut buffer = Vec::new();
|
|
parser
|
|
.process(b"doesn't contain the tok en", &mut buffer)
|
|
.expect("couldn't write to buffer");
|
|
assert_eq!(
|
|
"doesn't contain the tok en",
|
|
String::from_utf8_lossy(&buffer)
|
|
)
|
|
}
|