1use crate::arrangements::{ArrangeRow, ArrangementBlock, ArrangementFile, ARRANGEMENT_FILE_HEADER};
9
10use bincode;
11use itertools::Itertools;
12use serde::de::{
13 self, Deserializer, Error as DeserializeErr, IgnoredAny, MapAccess, SeqAccess, Visitor,
14};
15use serde::Deserialize;
16use serde_big_array::Array;
17use std::array::from_fn;
18use std::{fmt, str};
19
20fn get_bytes_from_seq<'de, A>(mut seq: A) -> Result<Vec<u8>, A::Error>
22where
23 A: SeqAccess<'de>,
24{
25 let mut v: Vec<u8> = vec![];
26 while seq.size_hint().unwrap_or(0) > 0 {
27 v.push(
28 seq.next_element()?
29 .ok_or_else(|| A::Error::custom("Could not access byte array sequence element"))?,
30 );
31 }
32
33 Ok(v)
34}
35
36impl<'de> Deserialize<'de> for ArrangementFile {
41 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
42 where
43 D: Deserializer<'de>,
44 {
45 enum Field {
46 Header,
47 DatatypeVersion,
48 Unk1,
49 ArrangementStateCurrent,
50 Unk2,
51 SavedFlag,
53 ArrangementStatePrevious,
54 ArrangementsSavedState,
56 CheckSum,
57 }
58
59 impl<'de> Deserialize<'de> for Field {
60 fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
61 where
62 D: Deserializer<'de>,
63 {
64 struct FieldVisitor;
65
66 impl Visitor<'_> for FieldVisitor {
67 type Value = Field;
68
69 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
70 formatter.write_str("ArrangementFile fields")
71 }
72
73 fn visit_str<E>(self, value: &str) -> Result<Field, E>
74 where
75 E: de::Error,
76 {
77 match value {
78 "header" => Ok(Field::Header),
79 "datatype_version" => Ok(Field::DatatypeVersion),
80 "unk1" => Ok(Field::Unk1),
81 "arrangement_state_current" => Ok(Field::ArrangementStateCurrent),
82 "unk2" => Ok(Field::Unk2),
83 "saved_flag" => Ok(Field::SavedFlag),
84 "arrangement_state_previous" => Ok(Field::ArrangementStatePrevious),
85 "arrangements_saved_state" => Ok(Field::ArrangementsSavedState),
86 "checksum" => Ok(Field::CheckSum),
87 _ => Err(de::Error::unknown_field(value, FIELDS)),
88 }
89 }
90 }
91
92 deserializer.deserialize_identifier(FieldVisitor)
93 }
94 }
95
96 struct ArrangementFileVisitor;
97
98 impl<'de> Visitor<'de> for ArrangementFileVisitor {
99 type Value = ArrangementFile;
100
101 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
102 formatter.write_str("struct ArrangementFile")
103 }
104
105 fn visit_seq<V>(self, seq: V) -> Result<Self::Value, V::Error>
110 where
111 V: SeqAccess<'de>,
112 {
113 let v: Vec<u8> = get_bytes_from_seq::<V>(seq)?;
114
115 let mut shift = 0;
116
117 let header: [u8; 21] = from_fn(|i| v[i + shift]);
118 shift += 21;
119
120 let datatype_version: u8 = v[shift];
121 shift += 1;
122
123 let unk1: [u8; 2] = from_fn(|i| v[i + shift]);
124 shift += 2;
125
126 let curr_arr_bytes: [u8; 5652] = from_fn(|i| v[i + shift]);
127 shift += 5650; let arrangement_state_current =
131 bincode::deserialize::<ArrangementBlock>(&curr_arr_bytes).unwrap_or_default();
132
133 let unk2: u8 = v[shift];
134 shift += 1;
135
136 let saved_flag: u8 = v[shift];
137 shift += 1;
138
139 let prev_arr_bytes: [u8; 5652] = from_fn(|i| v[i + shift]);
140 shift += 5650; let arrangement_state_previous =
144 bincode::deserialize::<ArrangementBlock>(&prev_arr_bytes).unwrap_or_default();
145
146 let arrangements_saved_state: [u8; 8] = from_fn(|i| v[i + shift]);
147 shift += 8;
148
149 let check_sum_arr: [u8; 2] = from_fn(|i| v[i + shift]);
151 let checksum = crate::u8_bytes_to_u16(&check_sum_arr);
154
155 Ok(Self::Value {
156 header,
157 datatype_version,
158 unk1,
159 arrangement_state_current,
160 unk2,
161 saved_flag,
162 arrangement_state_previous,
163 arrangements_saved_state,
164 checksum,
165 })
166 }
167
168 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
172 where
173 V: MapAccess<'de>,
174 {
175 let mut header = None;
176 let mut datatype_version = None;
177 let mut unk1 = None;
178 let mut arrangement_state_current = None;
179 let mut unk2 = None;
180 let mut saved_flag = None;
181 let mut arrangement_state_previous = None;
182 let mut arrangements_saved_state = None;
183 let mut checksum = None;
184
185 while let Some(key) = map.next_key()? {
186 match key {
187 Field::Header => {
188 if header.is_some() {
189 return Err(de::Error::duplicate_field("header"));
190 }
191 header = Some(map.next_value::<[u8; 21]>()?);
198 }
199 Field::DatatypeVersion => {
200 if datatype_version.is_some() {
201 return Err(de::Error::duplicate_field("datatype_version"));
202 }
203 datatype_version = Some(map.next_value::<u8>()?);
204 }
205 Field::Unk1 => {
206 if unk1.is_some() {
207 return Err(de::Error::duplicate_field("unk1"));
208 }
209 unk1 = Some(map.next_value::<[u8; 2]>()?);
210 }
211 Field::ArrangementStateCurrent => {
212 if arrangement_state_current.is_some() {
213 return Err(de::Error::duplicate_field(
214 "arrangement_state_current",
215 ));
216 }
217 arrangement_state_current = Some(map.next_value()?);
218 }
219 Field::Unk2 => {
220 if unk2.is_some() {
221 return Err(de::Error::duplicate_field("unk2"));
222 }
223 unk2 = Some(map.next_value()?);
224 }
225 Field::SavedFlag => {
226 if saved_flag.is_some() {
227 return Err(de::Error::duplicate_field("saved_flag"));
228 }
229 saved_flag = Some(map.next_value()?);
230 }
231 Field::ArrangementStatePrevious => {
232 if arrangement_state_previous.is_some() {
233 return Err(de::Error::duplicate_field(
234 "arrangement_state_previous",
235 ));
236 }
237 arrangement_state_previous = Some(map.next_value()?);
238 }
239 Field::ArrangementsSavedState => {
240 if arrangements_saved_state.is_some() {
241 return Err(de::Error::duplicate_field("arrangements_saved_state"));
242 }
243 arrangements_saved_state = Some(map.next_value()?);
244 }
245 Field::CheckSum => {
246 if checksum.is_some() {
247 return Err(de::Error::duplicate_field("checksum"));
248 }
249 checksum = Some(map.next_value()?);
250 }
251 }
252 }
253
254 let _header = header.ok_or_else(|| de::Error::missing_field("header"))?;
257 let datatype_version =
258 datatype_version.ok_or_else(|| de::Error::missing_field("datatype_version"))?;
259 let unk1 = unk1.ok_or_else(|| de::Error::missing_field("unk1"))?;
260 let arrangement_state_current = arrangement_state_current
261 .ok_or_else(|| de::Error::missing_field("arrangement_state_current"))?;
262 let unk2 = unk2.ok_or_else(|| de::Error::missing_field("unk2"))?;
263 let saved_flag =
264 saved_flag.ok_or_else(|| de::Error::missing_field("saved_flag"))?;
265 let arrangement_state_previous = arrangement_state_previous
266 .ok_or_else(|| de::Error::missing_field("arrangement_state_previous"))?;
267 let arrangements_saved_state = arrangements_saved_state
268 .ok_or_else(|| de::Error::missing_field("arrangements_saved_state"))?;
269 let checksum = checksum.ok_or_else(|| de::Error::missing_field("checksum"))?;
270
271 Ok(Self::Value {
272 header: ARRANGEMENT_FILE_HEADER,
273 datatype_version,
274 unk1,
275 arrangement_state_current,
276 unk2,
277 saved_flag,
278 arrangement_state_previous,
279 arrangements_saved_state,
280 checksum,
281 })
282 }
283 }
284
285 const FIELDS: &[&str] = &[
286 "header",
287 "datatype_version",
288 "unk1",
289 "arrangement_state_current",
290 "unk2",
291 "arrangement_state_previous",
292 "arrangements_saved_state",
293 "checksum",
294 ];
295
296 match deserializer.is_human_readable() {
297 true => deserializer.deserialize_map(ArrangementFileVisitor),
298 false => deserializer.deserialize_tuple(11336, ArrangementFileVisitor),
299 }
300 }
301}
302
303impl<'de> Deserialize<'de> for ArrangementBlock {
307 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
308 where
309 D: Deserializer<'de>,
310 {
311 struct ArrangementBlockVisitor;
312
313 impl<'de> Visitor<'de> for ArrangementBlockVisitor {
314 type Value = ArrangementBlock;
315
316 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
317 formatter.write_str("struct ArrangementBlock")
318 }
319
320 fn visit_seq<V>(self, seq: V) -> Result<ArrangementBlock, V::Error>
325 where
326 V: SeqAccess<'de>,
327 {
328 let v: Vec<u8> = get_bytes_from_seq::<V>(seq)?;
329
330 let name: [u8; 15] = from_fn(|x| v[x]);
331 let unknown_1: [u8; 2] = from_fn(|x| v[x + 15]);
332 let n_rows = v[17];
333
334 let rows: [ArrangeRow; 256] = from_fn(|i| {
335 match i >= n_rows as usize {
343 true => ArrangeRow::EmptyRow(),
344 false => {
345 let offset = 18;
346 let idx_start = offset + (i * 22);
347
348 let row_bytes: [u8; 22] = from_fn(|j| v[j + idx_start]);
349 bincode::deserialize::<ArrangeRow>(&row_bytes).unwrap_or_default()
351 }
352 }
353 });
354
355 let rows = Box::new(Array(rows));
356
357 Ok(ArrangementBlock {
358 name,
359 unknown_1,
360 n_rows,
361 rows,
362 })
363 }
364
365 fn visit_map<V>(self, mut map: V) -> Result<ArrangementBlock, V::Error>
369 where
370 V: MapAccess<'de>,
371 {
372 let mut name = None;
373 let mut unknown_1 = None;
374 let mut n_rows = None;
375 let mut rows = None;
376
377 while let Some(key) = map.next_key()? {
378 match key {
379 Some("name") => {
380 if name.is_some() {
381 return Err(de::Error::duplicate_field("name"));
382 }
383 name = Some(map.next_value()?);
384 }
385 Some("unknown_1") => {
386 if unknown_1.is_some() {
387 return Err(de::Error::duplicate_field("unknown_1"));
388 }
389 unknown_1 = Some(map.next_value()?);
390 }
391 Some("n_rows") => {
392 if n_rows.is_some() {
393 return Err(de::Error::duplicate_field("n_rows"));
394 }
395 n_rows = Some(map.next_value()?);
396 }
397 Some("rows") => {
398 if rows.is_some() {
399 return Err(de::Error::duplicate_field("rows"));
400 }
401 rows = Some(map.next_value()?);
402 }
403 _ => {
404 return Err(de::Error::custom(format![
405 "Did not recognise ArrangementBlock key: {:?}",
406 key.unwrap(),
407 ]));
408 }
409 }
410 }
411 let name = name.ok_or_else(|| de::Error::missing_field("name"))?;
412 let unknown_1 = unknown_1.ok_or_else(|| de::Error::missing_field("unknown_1"))?;
413 let n_rows = n_rows.ok_or_else(|| de::Error::missing_field("n_rows"))?;
414 let rows = rows.ok_or_else(|| de::Error::missing_field("rows"))?;
415
416 Ok(ArrangementBlock {
417 name,
418 unknown_1,
419 n_rows,
420 rows,
421 })
422 }
423 }
424
425 match deserializer.is_human_readable() {
426 true => deserializer.deserialize_map(ArrangementBlockVisitor),
427 false => deserializer.deserialize_tuple(5650, ArrangementBlockVisitor),
428 }
429 }
430}
431
432impl<'de> Deserialize<'de> for ArrangeRow {
449 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
450 where
451 D: Deserializer<'de>,
452 {
453 struct ArrangeRowVisitor;
454
455 impl<'de> Visitor<'de> for ArrangeRowVisitor {
456 type Value = ArrangeRow;
457
458 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
459 formatter.write_str("enum ArrangeRow")
460 }
461
462 fn visit_seq<V>(self, seq: V) -> Result<ArrangeRow, V::Error>
467 where
468 V: SeqAccess<'de>,
469 {
470 let v: Vec<u8> = get_bytes_from_seq::<V>(seq)?;
471
472 if v.len() != 22 {
473 return Err(de::Error::invalid_length(v.len(), &self));
474 }
475
476 let row_type = v[0];
477 let row_data = v[1..].to_vec();
478
479 if row_data.len() != 21 {
480 return Err(de::Error::custom(format![
481 "ArrangeRow: Invalid row data length, must be 21 bytes, received: {:?}",
482 row_data.len()
483 ]));
484 }
485
486 match row_type {
489 0 => {
490 let pattern_id = row_data[0];
491 let repetitions = row_data[1];
492 let mute_mask = row_data[3];
494 let tempo_1 = row_data[5];
496 let tempo_2 = row_data[6];
497 let scene_a = row_data[7];
498 let scene_b = row_data[8];
499 let offset = row_data[10];
501 let length = row_data[12];
506
507 let midi_transpose: [u8; 8] = from_fn(|x| row_data[x + 13]);
508
509 if repetitions > 63 {
510 return Err(de::Error::custom(format![
511 "ArrangeRow::PatternRow: Too many repetitions, must be <= 63: rep={repetitions:?}",
512 ]));
513 }
514
515 let x = ArrangeRow::PatternRow {
516 pattern_id,
517 repetitions,
518 mute_mask,
519 tempo_1,
520 tempo_2,
521 scene_a,
522 scene_b,
523 offset,
524 length,
525 midi_transpose,
526 };
527 Ok(x)
528 }
529 1 => {
530
531 let loop_count = row_data[0];
532 let row_target = row_data[1];
533
534 if loop_count > 100_u8 {
535 return Err(de::Error::custom(format![
536 "ArrangeRow::LoopOrJumpOrHaltRow: Loop count cannot exceed 100 (99x). loops={loop_count:?}",
537 ]));
538 }
539 let x = ArrangeRow::LoopOrJumpOrHaltRow {
540 loop_count,
541 row_target,
542 };
543 Ok(x)
544 }
545 2 => {
546 let mut row_data = row_data[0..=14].to_vec();
547 let first_invalid: Option<(usize, &u8)> = row_data.iter().find_position(|x| { **x < 32 || **x > 126 });
549 if let Some((x, _)) = first_invalid {
550 row_data = row_data[..x].to_vec();
551 }
552 let s = String::from_utf8(row_data)
553 .unwrap_or("ERROR".to_string())
554 .to_ascii_uppercase();
555
556 Ok(ArrangeRow::ReminderRow(s))
557 }
558 _ => {
559 Err(de::Error::custom(
560 format!["Invalid row type: {row_type:?} -- must be 0 (PatternRow/EmptyRow) / 1 (LoopOrHaltOrJump) / 2 (Reminder)"]
561 ))
562 }
563 }
564 }
565
566 fn visit_map<V>(self, mut map: V) -> Result<ArrangeRow, V::Error>
570 where
571 V: MapAccess<'de>,
572 {
573 let k = map.next_key()?;
575 match k {
576 Some("empty") => {
577 let _ = map.next_value::<IgnoredAny>()?;
578 Ok(ArrangeRow::EmptyRow())
579 }
580 Some("reminder") => Ok(ArrangeRow::ReminderRow(map.next_value::<String>()?)),
581 Some("pattern_id") => {
582 let pattern_id = map.next_value::<u8>()?;
583 let repetitions = map.next_entry::<&str, u8>()?.unwrap_or(("", 0)).1;
584 let mute_mask = map.next_entry::<&str, u8>()?.unwrap_or(("", 0)).1;
585 let tempo_1 = map.next_entry::<&str, u8>()?.unwrap_or(("", 0)).1;
586 let tempo_2 = map.next_entry::<&str, u8>()?.unwrap_or(("", 0)).1;
587 let scene_a = map.next_entry::<&str, u8>()?.unwrap_or(("", 0)).1;
588 let scene_b = map.next_entry::<&str, u8>()?.unwrap_or(("", 0)).1;
589 let offset = map.next_entry::<&str, u8>()?.unwrap_or(("", 0)).1;
590 let length = map.next_entry::<&str, u8>()?.unwrap_or(("", 0)).1;
591 let midi_transpose = map
592 .next_entry()?
593 .unwrap_or(("", [0, 0, 0, 0, 0, 0, 0, 0]))
594 .1;
595
596 Ok(ArrangeRow::PatternRow {
597 pattern_id,
598 repetitions,
599 mute_mask,
600 tempo_1,
601 tempo_2,
602 scene_a,
603 scene_b,
604 offset,
605 length,
606 midi_transpose,
607 })
608 }
609 Some("loop_count") => {
610 let loop_count = map.next_value::<u8>()?;
611 let _ = map.next_key::<IgnoredAny>()?;
612 let row_target = map.next_value::<u8>()?;
613
614 Ok(ArrangeRow::LoopOrJumpOrHaltRow {
615 loop_count,
616 row_target,
617 })
618 }
619 _ => Err(de::Error::custom(format![
620 "Did not recognise ArrangeRow type based on first key: {:?}",
621 k.unwrap()
622 ])),
623 }
624 }
625 }
626
627 match deserializer.is_human_readable() {
628 true => deserializer.deserialize_map(ArrangeRowVisitor),
629 false => deserializer.deserialize_tuple(22, ArrangeRowVisitor),
630 }
631 }
632}
633
634#[cfg(test)]
635#[allow(unused_imports)]
636mod tests {
637 use super::*;
638
639 mod arrangement_file {
640 use crate::test_utils::get_arrange_dirpath;
641 use crate::OctatrackFileIO;
642
643 #[test]
644 fn read_binfile_blank() {
645 let path = get_arrange_dirpath().join("blank.work");
646 let r = super::ArrangementFile::from_data_file(&path);
647 println!("{r:?}");
648 assert!(r.is_ok());
649 }
650
651 #[test]
652 fn read_binfile_full_options() {
653 let path = get_arrange_dirpath().join("full-options.work");
654 let r = super::ArrangementFile::from_data_file(&path);
655 println!("{r:?}");
656 assert!(r.is_ok());
657 }
658
659 #[test]
660 fn read_binfile_one_reminder_row() {
661 let path = get_arrange_dirpath().join("1-rem-blank-txt.work");
662 let r = super::ArrangementFile::from_data_file(&path);
663 println!("{r:?}");
664 assert!(r.is_ok());
665 }
666 }
667
668 mod arrangement_block {
669 #[test]
670 fn empty_rows() {
671 use crate::arrangements::ArrangeRow;
672
673 let expected_rows: [ArrangeRow; 256] = std::array::from_fn(|i| {
674 if i < 10 {
675 ArrangeRow::PatternRow {
676 pattern_id: 0,
677 repetitions: 0,
678 mute_mask: 0,
679 tempo_1: 0,
680 tempo_2: 0,
681 scene_a: 0,
682 scene_b: 0,
683 offset: 0,
684 length: 0,
685 midi_transpose: [0, 0, 0, 0, 0, 0, 0, 0],
686 }
687 } else {
688 ArrangeRow::EmptyRow()
689 }
690 });
691
692 let rows = Box::new(serde_big_array::Array(expected_rows));
693
694 let expected = super::ArrangementBlock {
695 name: [10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
696 unknown_1: [10, 9],
697 n_rows: 10,
698 rows,
699 };
700
701 let b: [u8; 5652] = std::array::from_fn(|x| {
702 match x {
703 0 => 10,
705 14 => 10,
707 15 => 10,
709 16 => 9,
711 17 => 10,
713 _ => 0,
714 }
715 });
716
717 let r = bincode::deserialize::<super::ArrangementBlock>(&b);
718 assert_eq!(expected, r.unwrap());
719 }
720 }
721
722 mod arrange_row {
723 use super::*;
724
725 #[test]
726 fn invalid_row_type() {
727 let b = [
728 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
729 ];
730 let r = bincode::deserialize::<ArrangeRow>(&b);
731 assert!(r.is_err());
732 }
733
734 mod empty_row {
735 #[test]
745 fn row_index_matters() {
746 let not_expected = super::ArrangeRow::EmptyRow();
747 let expected = super::ArrangeRow::PatternRow {
748 pattern_id: 0,
749 repetitions: 0,
750 mute_mask: 0,
751 tempo_1: 0,
752 tempo_2: 0,
753 scene_a: 0,
754 scene_b: 0,
755 offset: 0,
756 length: 0,
757 midi_transpose: [0, 0, 0, 0, 0, 0, 0, 0],
758 };
759
760 let b = [
761 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
762 ];
763 let r = bincode::deserialize::<super::ArrangeRow>(&b);
764 println!("{r:?}");
765 assert!(r.is_ok());
766 let x = r.unwrap();
767 assert_ne!(not_expected, x);
768 assert_eq!(expected, x);
769 }
770
771 #[test]
772 fn valid_yaml() {
773 let expected = super::ArrangeRow::EmptyRow();
774 let s = "empty: ''\n";
775 let r = serde_yml::from_str::<super::ArrangeRow>(s);
776 println!("{r:?}");
777 assert!(r.is_ok());
778 assert_eq!(expected, r.unwrap());
779 }
780
781 #[test]
782 fn valid_json() {
783 let expected = super::ArrangeRow::EmptyRow();
784 let s = "{\"empty\":\"\"}";
785 let r = serde_json::from_str::<super::ArrangeRow>(s);
786 println!("{r:?}");
787 assert!(r.is_ok());
788 assert_eq!(expected, r.unwrap());
789 }
790 }
791
792 mod reminder_row {
793 #[test]
794 fn valid() {
795 let expected = super::ArrangeRow::ReminderRow("CCCCCCCCCCCCCCC".to_string());
796 let b = [
797 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 0, 0, 0, 0, 0, 0,
798 ];
799 let r = bincode::deserialize::<super::ArrangeRow>(&b);
800 assert_eq!(expected, r.unwrap());
801 }
802
803 #[test]
804 fn valid_yaml() {
805 let expected = super::ArrangeRow::ReminderRow("CCCCCCCCCCCCCCC".to_string());
806
807 let s = "reminder: CCCCCCCCCCCCCCC\n";
808 let r = serde_yml::from_str::<super::ArrangeRow>(s);
809 assert_eq!(expected, r.unwrap());
810 }
811
812 #[test]
813 fn valid_drop_excess_characters() {
814 let expected = super::ArrangeRow::ReminderRow("CCCCCCCCCCCCCCC".to_string());
815 let b = [
816 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
817 99, 99,
818 ];
819 let r = bincode::deserialize::<super::ArrangeRow>(&b);
820 assert_eq!(expected, r.unwrap());
821 }
822 }
823 mod loop_jump_or_halt_row {
824 #[test]
825 fn valid() {
826 let expected = super::ArrangeRow::LoopOrJumpOrHaltRow {
827 loop_count: 1,
828 row_target: 1,
829 };
830 let b = [
831 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
832 ];
833 let r = bincode::deserialize::<super::ArrangeRow>(&b);
834 assert_eq!(expected, r.unwrap());
835 }
836
837 #[test]
838 #[ignore]
839 fn valid_yaml() {
840 let expected = super::ArrangeRow::LoopOrJumpOrHaltRow {
841 loop_count: 1,
842 row_target: 1,
843 };
844
845 let s = "loop_count: 1\nrow_target: 1\n";
846 let r = serde_yml::from_str::<super::ArrangeRow>(s);
847 assert_eq!(expected, r.unwrap());
848 }
849
850 #[test]
851 fn invalid_loop_count() {
852 let b = [
853 1, 101, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
854 ];
855 let r = bincode::deserialize::<super::ArrangeRow>(&b);
856 assert!(r.is_err());
857 }
858 }
859
860 mod pattern_row {
861
862 #[test]
863 fn valid_pattern_id_only() {
864 let expected = super::ArrangeRow::PatternRow {
865 pattern_id: 1,
866 repetitions: 0,
867 mute_mask: 0,
868 tempo_1: 0,
869 tempo_2: 0,
870 scene_a: 0,
871 scene_b: 0,
872 offset: 0,
873 length: 0,
874 midi_transpose: [0, 0, 0, 0, 0, 0, 0, 0],
875 };
876 let b = [
877 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
878 ];
879 let r = bincode::deserialize::<super::ArrangeRow>(&b);
880 assert_eq!(expected, r.unwrap());
881 }
882
883 #[test]
884 fn valid_last_midi_transpose_only() {
885 let expected = super::ArrangeRow::PatternRow {
886 pattern_id: 0,
887 repetitions: 0,
888 mute_mask: 0,
889 tempo_1: 0,
890 tempo_2: 0,
891 scene_a: 0,
892 scene_b: 0,
893 offset: 0,
894 length: 0,
895 midi_transpose: [0, 0, 0, 0, 0, 0, 0, 8],
896 };
897 let b = [
898 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,
899 ];
900 let r = bincode::deserialize::<super::ArrangeRow>(&b);
901 assert_eq!(expected, r.unwrap());
902 }
903
904 #[test]
905 fn invalid_too_many_repetitions() {
906 let b = [
907 0, 1, 64, 1, 1, 1, 1, 1, 15, 15, 1, 1, 1, 64, 3, 3, 3, 3, 3, 3, 3, 3,
908 ];
909 let r = bincode::deserialize::<super::ArrangeRow>(&b);
910 println!("{r:?}");
911 assert!(r.is_err());
912 }
913
914 #[test]
915 fn valid_all() {
916 let expected = super::ArrangeRow::PatternRow {
917 pattern_id: 1,
918 repetitions: 10,
919 mute_mask: 1,
920 tempo_1: 1,
921 tempo_2: 1,
922 scene_a: 15,
923 scene_b: 15,
924 offset: 1,
925 length: 64,
926 midi_transpose: [3, 3, 3, 3, 3, 3, 3, 3],
927 };
928 let b = [
929 0, 1, 10, 1, 1, 1, 1, 1, 15, 15, 1, 1, 1, 64, 3, 3, 3, 3, 3, 3, 3, 3,
930 ];
931 let r = bincode::deserialize::<super::ArrangeRow>(&b);
932 assert_eq!(expected, r.unwrap());
933 }
934
935 #[test]
936 fn zero_valued_is_still_pattern_row() {
937 let expected = super::ArrangeRow::PatternRow {
938 pattern_id: 0,
939 repetitions: 0,
940 mute_mask: 0,
941 tempo_1: 0,
942 tempo_2: 0,
943 scene_a: 0,
944 scene_b: 0,
945 offset: 0,
946 length: 0,
947 midi_transpose: [0, 0, 0, 0, 0, 0, 0, 0],
948 };
949 let b = [
950 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
951 ];
952 let r = bincode::deserialize::<super::ArrangeRow>(&b);
953 assert_eq!(expected, r.unwrap());
954 }
955 }
956 }
957}