2021 day16/rust: clean up

This commit is contained in:
Xiretza 2021-12-16 20:36:23 +01:00
parent f24e06da7d
commit 0220f88e27

View file

@ -7,7 +7,6 @@ use std::{
use nom::{ use nom::{
bits::complete as bits, bits::complete as bits,
combinator::flat_map,
multi::{many0, many_m_n}, multi::{many0, many_m_n},
}; };
use nom::{combinator::map, sequence::pair}; use nom::{combinator::map, sequence::pair};
@ -53,58 +52,64 @@ enum PacketType {
} }
impl PacketType { impl PacketType {
pub fn parse(input: Input) -> IResult<PacketType> { pub fn parse(i: Input) -> IResult<PacketType> {
flat_map(bits::take(3_usize), |type_id: u8| { let (i, operator) = map(bits::take(3_usize), |type_id: u8| {
move |i| match Operator::try_from(type_id) { Operator::try_from(type_id)
Ok(operator) => map(Self::operation_inner, |sub_packets| PacketType::Operation { })(i)?;
match operator {
Ok(operator) => map(Self::parse_sub_packets, |sub_packets| {
PacketType::Operation {
operator, operator,
sub_packets, sub_packets,
})(i), }
Err(_) => map(Self::literal_inner, PacketType::Literal)(i), })(i),
} Err(_) => map(Self::parse_literal_value, PacketType::Literal)(i),
})(input) }
} }
fn operation_inner(i: Input) -> IResult<Vec<Packet>> { fn parse_sub_packets(i: Input) -> IResult<Vec<Packet>> {
enum LengthType { enum LengthType {
Bits(u16), Bits(usize),
Packets(u16), Packets(usize),
} }
flat_map( impl LengthType {
flat_map(bits::take(1_usize), |length_type_id: u8| { pub fn parse(i: Input) -> IResult<Self> {
move |i| match length_type_id { let (i, length_type_id) = bits::take(1_usize)(i)?;
match length_type_id {
0 => map(bits::take(15_usize), LengthType::Bits)(i), 0 => map(bits::take(15_usize), LengthType::Bits)(i),
1 => map(bits::take(11_usize), LengthType::Packets)(i), 1 => map(bits::take(11_usize), LengthType::Packets)(i),
_ => unreachable!(), _ => unreachable!(),
} }
}), }
|length_type| { }
move |i| match length_type {
LengthType::Packets(n) => {
many_m_n(usize::from(n), usize::from(n), Packet::parse)(i)
}
LengthType::Bits(n) => {
// map_parser(recognize(bits::take(n)), many1(Packet::parse))(i)
let extra_bytes_required = (usize::from(n) + i.1) / 8;
let extra_bits_required = (usize::from(n) + i.1) % 8;
let subpackets_slice = (&i.0[..=extra_bytes_required], i.1); let (i, length_type) = LengthType::parse(i)?;
let (subpackets_end, subpackets) = many0(Packet::parse)(subpackets_slice)?; match length_type {
if subpackets_end.0.len() > 1 { LengthType::Packets(n) => many_m_n(n, n, Packet::parse)(i),
todo!() LengthType::Bits(n) => {
} // manual implementation of something like the following:
Ok(( // map_parser(recognize(bits::take(n)), many0(Packet::parse))(i)
(&i.0[extra_bytes_required..], extra_bits_required),
subpackets, let new_byte_offset = (n + i.1) / 8;
)) let new_bit_offset = (n + i.1) % 8;
}
} let subpackets_input = (&i.0[..=new_byte_offset], i.1);
}, let (subpackets_end, subpackets) = many0(Packet::parse)(subpackets_input)?;
)(i)
let new_input = (&i.0[new_byte_offset..], new_bit_offset);
assert_eq!(subpackets_end, new_input);
Ok((
new_input,
subpackets,
))
}
}
} }
fn literal_inner(i: Input) -> IResult<usize> { fn parse_literal_value(i: Input) -> IResult<usize> {
fold_till( fold_till(
pair(bits::take(1_usize), bits::take(4_usize)), pair(bits::take(1_usize), bits::take(4_usize)),
|| 0, || 0,
@ -122,8 +127,8 @@ impl PacketType {
match self { match self {
Self::Literal(n) => *n, Self::Literal(n) => *n,
Self::Operation { Self::Operation {
ref operator, operator,
ref sub_packets, sub_packets,
} => operator.evaluate(sub_packets.iter().map(|p| p.typ.evaluate())), } => operator.evaluate(sub_packets.iter().map(|p| p.typ.evaluate())),
} }
} }