Skip to main content

polytrack_codes/v1/
mod.rs

1#![allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
2#[cfg(test)]
3mod tests;
4
5use std::collections::BTreeMap;
6
7use facet::Facet;
8
9#[derive(Debug, Facet)]
10struct JsonTrack {
11    version: u32,
12    name: String,
13    track: String,
14}
15
16#[derive(Debug, PartialEq, Eq, Clone)]
17pub struct Track {
18    pub version: u32,
19    pub name: String,
20    pub track: TrackInfo,
21}
22
23#[derive(Debug, Facet, PartialEq, Eq)]
24struct JsonTrackInfo {
25    pub version: u32,
26    pub parts: BTreeMap<String, Vec<i32>>,
27}
28
29#[derive(Debug, PartialEq, Eq, Clone)]
30pub struct TrackInfo {
31    pub version: u32,
32    pub parts: Vec<Part>,
33}
34
35#[derive(Debug, PartialEq, Eq, Clone)]
36pub struct Part {
37    pub id: u32,
38    pub blocks: Vec<Block>,
39}
40
41#[derive(Debug, PartialEq, Eq, Clone)]
42pub struct Block {
43    pub x: i32,
44    pub y: i32,
45    pub z: i32,
46    pub rot: u8,
47}
48
49#[must_use]
50pub fn decode_track_code(track_code: &str) -> Option<Track> {
51    let json_track: JsonTrack = facet_json::from_str(track_code).ok()?;
52    let json_track_info: JsonTrackInfo = facet_json::from_str(&json_track.track).ok()?;
53    let mut track_info = TrackInfo {
54        version: json_track_info.version,
55        parts: json_track_info
56            .parts
57            .into_iter()
58            .map(|(id, blocks)| Part {
59                id: id.parse().unwrap_or_default(),
60                blocks: blocks
61                    .chunks_exact(4)
62                    .map(|block| Block {
63                        x: block[0],
64                        y: block[1],
65                        z: block[2],
66                        rot: block[3] as u8,
67                    })
68                    .collect(),
69            })
70            .collect(),
71    };
72    track_info.parts.sort_by_key(|part| part.id);
73    Some(Track {
74        version: json_track.version,
75        name: json_track.name,
76        track: track_info,
77    })
78}
79
80#[must_use]
81#[allow(clippy::missing_panics_doc)]
82pub fn encode_track_code(track: Track) -> String {
83    let parts = track
84        .track
85        .parts
86        .into_iter()
87        .map(|p| {
88            format!(
89                r#""{}":[{}]"#,
90                p.id,
91                p.blocks
92                    .into_iter()
93                    .flat_map(|b| vec![b.x, b.y, b.z, b.rot.into()])
94                    .map(|n| n.to_string())
95                    .collect::<Vec<_>>()
96                    .join(",")
97            )
98        })
99        .collect::<Vec<_>>()
100        .join(",");
101    let json_track_info = format!(r#"{{"version":{},"parts":{{{}}}}}"#, track.version, parts);
102    let json_track = JsonTrack {
103        version: track.version,
104        name: track.name,
105        track: json_track_info,
106    };
107    facet_json::to_string(&json_track).expect("should never fail")
108}