pub fn parse<T: Clone, E: Into<Box<dyn Error>>>(
input: &str,
padding: usize,
default_value: T,
hot_map: impl Fn(u8) -> T,
hot_valid: impl Fn(u8) -> bool,
slow_map: impl FnMut(usize, u8) -> Result<T, E>,
) -> Result<Grid<T>, InputError>
Expand description
Parse a 2D grid.
This function assumes that each byte represents one item in the grid. Using 1 byte wide output types is recommended to enable more efficient vectorization.
Parsing is done in two passes per line:
-
A “hot” pass, where each byte is mapped to an output value and checked for validity. This uses the
hot_map
andhot_valid
functions, which should be pure and total mappings fromu8
to their respective outputs to enable vectorization. Additionally,hot_valid
must return false for both'\r'
and'\n'
. -
A “slow” pass, where any invalid bytes from the first pass are re-processed with their index in the final grid. This uses the
slow_map
function which returns aResult
, containing either a mapped value or an error.slow_map
can be used to perform more complex, non-pure, mappings such as storing positions and will never be called for newlines or bytes that were valid in the first pass. If all the bytes were valid in the first pass, this pass is skipped.
default_value
is used to initialize the grid before parsing and for any padding.
A value with an all-zero bit pattern will usually faster to initialize and is recommended when
padding is not used.
Returns (number of rows, number of columns, data) on success.
§Examples
assert_eq!(
grid::parse(
/* input */ "##.#\n#..#\n#.##",
/* padding */ 0,
/* default_value */ false,
/* hot_map */ |b| b == b'#',
/* hot_valid */ |b| matches!(b, b'.' | b'#'),
/* slow_map */ |_, _| Err("expected '.' or '#'"),
).unwrap(),
(3, 4, vec![
true, true, false, true,
true, false, false, true,
true, false, true, true,
]),
);
assert_eq!(
grid::parse(
/* input */"##.#\n#..#\n#.##",
/* padding */ 2,
/* default_value */ false,
/* hot_map */ |b| b == b'#',
/* hot_valid */ |b| matches!(b, b'.' | b'#'),
/* slow_map */ |_, _| Err("expected '.' or '#'"),
).unwrap(),
(7, 8, vec![
false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false,
false, false, true, true, false, true, false, false,
false, false, true, false, false, true, false, false,
false, false, true, false, true, true, false, false,
false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false,
]),
);
let mut start = None;
assert_eq!(
grid::parse(
/* input */ ".0.#S\r\n..1..\r\n.###2\r\n.3...",
/* padding */ 1,
/* default_value */ b'#',
/* hot_map */ |b| b,
/* hot_valid */ |b| matches!(b, b'.' | b'#' | b'0'..=b'9'),
/* slow_map */ |i, b| {
match b {
b'S' if start.is_none() => {
start = Some(i);
Ok(b'.')
},
b'S' => Err("expected only one 'S'"),
_ => Err("expected '.', '#', 'S' or a digit")
}
},
).unwrap(),
(6, 7, vec![
b'#', b'#', b'#', b'#', b'#', b'#', b'#',
b'#', b'.', b'0', b'.', b'#', b'.', b'#',
b'#', b'.', b'.', b'1', b'.', b'.', b'#',
b'#', b'.', b'#', b'#', b'#', b'2', b'#',
b'#', b'.', b'3', b'.', b'.', b'.', b'#',
b'#', b'#', b'#', b'#', b'#', b'#', b'#',
]),
);
assert_eq!(start, Some(12));