rhythm_open_exchange/codec/formats/
jrox.rs1use crate::codec::{Decoder, Encoder, Format};
6use crate::error::{RoxError, RoxResult};
7use crate::model::RoxChart;
8
9pub struct JroxDecoder;
11
12pub struct JroxEncoder;
14
15const MAX_FILE_SIZE: usize = 100 * 1024 * 1024;
17
18impl Decoder for JroxDecoder {
19 fn decode(data: &[u8]) -> RoxResult<RoxChart> {
20 if data.len() > MAX_FILE_SIZE {
21 return Err(RoxError::InvalidFormat(format!(
22 "File too large: {} bytes (max {}MB)",
23 data.len(),
24 MAX_FILE_SIZE / 1024 / 1024
25 )));
26 }
27 let chart: RoxChart = serde_json::from_slice(data)
33 .map_err(|e| RoxError::InvalidFormat(format!("JROX parse error: {e}")))?;
34
35 Ok(chart)
36 }
37}
38
39impl Encoder for JroxEncoder {
40 fn encode(chart: &RoxChart) -> RoxResult<Vec<u8>> {
41 serde_json::to_vec_pretty(chart).map_err(|e| RoxError::Serialize(e.to_string()))
42 }
43}
44
45impl Format for JroxDecoder {
46 const EXTENSIONS: &'static [&'static str] = &["jrox"];
47}
48
49impl Format for JroxEncoder {
50 const EXTENSIONS: &'static [&'static str] = &["jrox"];
51}
52
53#[cfg(test)]
54mod tests {
55 use compact_str::ToCompactString;
56
57 use super::*;
58 use crate::codec::{Decoder, Encoder};
59 use crate::model::RoxChart;
60
61 #[test]
62 fn test_jrox_roundtrip() {
63 let mut chart = RoxChart::new(4);
64 chart.metadata.title = "Jrox Test".to_compact_string();
65
66 let encoded = JroxEncoder::encode(&chart).unwrap();
67 let decoded = JroxDecoder::decode(&encoded).unwrap();
68
69 assert_eq!(chart.key_count(), decoded.key_count());
70 assert_eq!(chart.metadata.title, decoded.metadata.title);
71 }
72
73 #[test]
74 fn test_file_too_large() {
75 let big_data = vec![0; MAX_FILE_SIZE + 1];
76 let result = JroxDecoder::decode(&big_data);
77 assert!(
78 matches!(result, Err(RoxError::InvalidFormat(msg)) if msg.contains("File too large"))
79 );
80 }
81}