1use super::{ByteInput as Input, cbv::cstr, prelude::*};
4
5#[derive(Clone, Copy, Debug)]
6pub struct Header {
7 pub len: usize,
8 pub avl_root: u32,
9 pub first_deleted: Option<usize>,
10 pub record_len: usize,
11 pub len_existing: usize,
12}
13
14pub fn header(input: &mut Input<'_>) -> ModalResult<Header> {
15 let len = le_u32.parse_next(input)? as usize;
16 let avl_root = le_u32.parse_next(input)?;
17 let one_to_zero = le_u32.parse_next(input)?;
18 assert_eq!(one_to_zero, 1234567890);
19 let record_len = le_u32.parse_next(input)? as usize;
20 let first_deleted = le_i32.map(|x| (x != -1).then_some(x as usize)).parse_next(input)?;
24 let len_existing = le_u32.parse_next(input)? as usize;
25 let more_offset = le_u32.parse_next(input)?;
28 assert!(more_offset == 0 || more_offset == 4);
29 let padding = take(more_offset).parse_next(input)?;
32 assert!(padding.iter().all(|x| *x == 0));
33
34 Ok(Header { len, avl_root, record_len, first_deleted, len_existing })
35}
36
37fn optional1(x: i32) -> Option<usize> {
42 assert!(x >= -1);
43 if x == -1 { None } else { Some(x as usize) }
44}
45
46#[derive(Clone, Debug)]
47pub struct Record {
48 pub deleted: bool,
49 pub first_name: String,
50 pub last_name: String,
51 pub games: usize,
52 pub first_game: usize,
53}
54
55pub fn record(input: &mut Input<'_>) -> ModalResult<Record> {
56 let (left_child, deleted) = le_i32
57 .map(|x| if x == -999 { (None, true) } else { (optional1(x), false) })
58 .parse_next(input)?;
59 let (right_child, next_deleted) = le_i32
60 .map(|x| if deleted { (None, optional1(x)) } else { (optional1(x), None) })
61 .parse_next(input)?;
62 let right_height_minus_left_height = i8.parse_next(input)?;
63 if deleted {
64 assert_eq!(right_height_minus_left_height, 0)
65 };
66 let last_name = take(30u8).map(cstr).parse_next(input)?;
67 let first_name = take(20u8).map(cstr).parse_next(input)?;
68 let games = le_u32.parse_next(input)? as usize;
69 let first_game = le_u32.parse_next(input)? as usize;
70
71 let _ = (left_child, right_child, next_deleted);
72
73 Ok(Record { deleted, first_name, last_name, games, first_game })
74}
75
76#[derive(Clone, Debug)]
77pub struct Players {
78 pub header: Header,
79 pub records: Vec<Record>,
80}
81
82pub fn players(input: &mut Input<'_>) -> ModalResult<Players> {
83 let header = header.parse_next(input)?;
84 let records: Vec<Record> = repeat(..=header.len, record).parse_next(input)?;
85 Ok(Players { header, records })
86}
87
88#[test]
89fn example() {
90 let input = include_bytes!("../../examples/twic1616.cbp");
91 let header = header.parse_next(&mut input.as_slice()).expect("can parse CBP header");
92 println!("{header:?}");
93 let players = players.parse(input.as_slice()).map_err(drop).expect("can parse CBP file");
94 println!("{:?}", players.header);
95 for player in players.records.iter().take(3) {
96 println!("{player:?}");
97 }
98 for player in players.records.iter().rev().take(3) {
99 println!("{player:?}");
100 }
101}