polytrack_codes/v1/
mod.rs1#![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}