1use nom::{
2 character::complete::{multispace0, space1},
3 combinator::map_opt,
4 sequence::separated_pair,
5 IResult, ParseTo,
6};
7
8use crate::{helpers::*, BoundingBox, Coord};
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct Metadata {
13 pub version: f32,
15
16 pub name: String,
18
19 pub point_size: i32,
21
22 pub resolution: Coord,
24
25 pub bounding_box: BoundingBox,
27}
28
29impl Metadata {
30 pub(crate) fn parse(input: &[u8]) -> IResult<&[u8], Self> {
31 let (input, version) = skip_comments(metadata_version)(input)?;
32 let (input, name) = skip_comments(metadata_name)(input)?;
33 let (input, (point_size, resolution)) = skip_comments(metadata_size)(input)?;
34 let (input, bounding_box) = skip_comments(metadata_bounding_box)(input)?;
35 let (input, _) = multispace0(input)?;
36
37 Ok((
38 input,
39 Self {
40 version,
41 name,
42 point_size,
43 resolution,
44 bounding_box,
45 },
46 ))
47 }
48}
49
50fn metadata_version(input: &[u8]) -> IResult<&[u8], f32> {
51 map_opt(statement("STARTFONT", parse_string), |v: String| {
52 v.as_str().parse_to()
53 })(input)
54}
55
56fn metadata_name(input: &[u8]) -> IResult<&[u8], String> {
57 statement("FONT", parse_string)(input)
58}
59
60fn metadata_size(input: &[u8]) -> IResult<&[u8], (i32, Coord)> {
61 statement("SIZE", separated_pair(parse_to_i32, space1, Coord::parse))(input)
62}
63
64fn metadata_bounding_box(input: &[u8]) -> IResult<&[u8], BoundingBox> {
65 statement("FONTBOUNDINGBOX", BoundingBox::parse)(input)
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn parse_bdf_version() {
74 assert_parser_ok!(metadata_version(b"STARTFONT 2.1\n"), 2.1f32);
75
76 assert_parser_ok!(metadata_version(b"STARTFONT 2.1\n"), 2.1f32);
78 }
79
80 #[test]
81 fn parse_font_name() {
82 assert_parser_ok!(metadata_name(b"FONT abc"), "abc".to_string());
83 }
84
85 #[test]
86 fn parse_metadata() {
87 let input = br#"STARTFONT 2.1
88FONT "test font"
89SIZE 16 75 100
90FONTBOUNDINGBOX 16 24 1 2"#;
91
92 assert_parser_ok!(
93 Metadata::parse(input),
94 Metadata {
95 version: 2.1,
96 name: String::from("\"test font\""),
97 point_size: 16,
98 resolution: Coord::new(75, 100),
99 bounding_box: BoundingBox {
100 size: Coord::new(16, 24),
101 offset: Coord::new(1, 2),
102 }
103 }
104 );
105 }
106}