ot_tools_io/projects/metadata.rs
1/*
2SPDX-License-Identifier: GPL-3.0-or-later
3Copyright © 2024 Mike Robeson [dijksterhuis]
4*/
5
6//! Type and parsing of a project's OS metadata.
7//! Used in the [`crate::projects::ProjectFile`] type.
8
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12use crate::projects::{
13 parse_hashmap_string_value, string_to_hashmap, ProjectParseError, SectionHeader,
14};
15
16/*
17Example data:
18[META]\r\nTYPE=OCTATRACK DPS-1 PROJECT\r\nVERSION=19\r\nOS_VERSION=R0177 1.40B\r\n[/META]
19------
20[META]
21TYPE=OCTATRACK DPS-1 PROJECT
22VERSION=19
23OS_VERSION=R0177 1.40B
24[/META]
25*/
26
27/// Operating system metadata read from a `project.*` file.
28/// The octatrack checks these fields on project load/open to ensure:
29/// 1. it is possible to load the project (the project is not from an unrecognised OS version where a patch has not yet been installed)
30/// 2. the project is upgraded to run on a newer OS version (need to patch the project data files as tey were created with an older OS)
31#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
32pub struct OsMetadata {
33 /// Type of file (always a 'project').
34 ///
35 /// Example ASCII data:
36 /// ```text
37 /// TYPE=OCTATRACK DPS-1 PROJECT
38 /// ```
39 pub filetype: String,
40
41 /// Version of `project.*` data type in this file, a la the `datatype_version` field on other main file types (probably?)
42 ///
43 /// Example ASCII data:
44 /// ```text
45 /// VERSION=19
46 /// ```
47 pub project_version: u32,
48
49 /// Version of the Octatrack OS (that the project was created with?).
50 ///
51 /// Example ASCII data:
52 /// ```text
53 /// OS_VERSION=R0177 1.40B
54 /// ```
55 pub os_version: String,
56}
57
58impl Default for OsMetadata {
59 fn default() -> Self {
60 Self {
61 filetype: "OCTATRACK DPS-1 PROJECT".to_string(),
62 project_version: 19,
63 os_version: "R0177 1.40B".to_string(),
64 }
65 }
66}
67
68impl std::str::FromStr for OsMetadata {
69 type Err = ProjectParseError;
70
71 /// Extract `OctatrackProjectMetadata` fields from the project file's ASCII data
72 fn from_str(s: &str) -> Result<Self, Self::Err> {
73 let hmap: HashMap<String, String> = string_to_hashmap(s, &SectionHeader::Meta)?;
74
75 Ok(Self {
76 filetype: parse_hashmap_string_value::<String>(&hmap, "type", None)
77 .map_err(|_| ProjectParseError::String)?,
78 project_version: parse_hashmap_string_value::<u32>(&hmap, "version", None)?,
79 os_version: parse_hashmap_string_value::<String>(&hmap, "os_version", None)
80 .map_err(|_| ProjectParseError::String)?,
81 })
82 }
83}
84
85impl std::fmt::Display for OsMetadata {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
87 let mut s = "".to_string();
88 s.push_str("[META]\r\n");
89 s.push_str(format!("TYPE={}", self.filetype).as_str());
90 s.push_str("\r\n");
91 s.push_str(format!("VERSION={}", self.project_version).as_str());
92 s.push_str("\r\n");
93 s.push_str(format!("OS_VERSION={}", self.os_version).as_str());
94 s.push_str("\r\n[/META]");
95 write!(f, "{s:#}")
96 }
97}