1pub mod entitlements;
14pub mod info_plist;
16pub mod prelude {
18 pub use super::entitlements::prelude::*;
19 pub use super::info_plist::prelude::*;
20 #[cfg(feature = "plist")]
21 pub use plist;
22}
23#[cfg(feature = "plist")]
24pub use plist::{
25 self, from_bytes, from_file, from_reader, from_reader_xml, to_file_binary, to_file_xml,
26 to_writer_binary, to_writer_xml,
27};
28
29use serde::{ser::SerializeSeq, Serialize, Serializer};
30
31fn serialize_enum_option<S: Serializer, T: Serialize>(
32 value: &Option<T>,
33 s: S,
34) -> Result<S::Ok, S::Error> {
35 s.serialize_str(&serde_plain::to_string(value).unwrap())
36}
37
38fn serialize_vec_enum_option<S: Serializer, T: Serialize>(
39 value: &Option<Vec<T>>,
40 s: S,
41) -> Result<S::Ok, S::Error> {
42 match value {
43 Some(ref val) => {
44 let mut seq = s.serialize_seq(Some(val.len()))?;
45 for element in val.iter() {
46 seq.serialize_element(&serde_plain::to_string(element).unwrap())?;
47 }
48 seq.end()
49 }
50 None => panic!("unsupported"),
51 }
52}
53
54fn serialize_option<S, T>(value: &Option<T>, ser: S) -> Result<S::Ok, S::Error>
55where
56 S: Serializer,
57 T: Serialize,
58{
59 value
60 .as_ref()
61 .expect(r#"`serialize_option` must be used with `skip_serializing_if = "Option::is_none"`"#)
62 .serialize(ser)
63}
64
65#[cfg(test)]
66mod tests {
67 use super::prelude::*;
68
69 pub const PLIST_FILE_NAME: &str = "Info.plist";
70
71 pub const PLIST_TEST_EXAMPLE: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
72<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
73<plist version="1.0">
74<dict>
75 <key>CFBundlePackageType</key>
76 <string>APPL</string>
77 <key>LSApplicationCategoryType</key>
78 <string>public.app-category.business</string>
79 <key>CFBundleIdentifier</key>
80 <string>com.test.test-id</string>
81 <key>CFBundleName</key>
82 <string>Test</string>
83 <key>CFBundleVersion</key>
84 <string>1</string>
85 <key>CFBundleShortVersionString</key>
86 <string>1.0</string>
87 <key>CFBundleInfoDictionaryVersion</key>
88 <string>1.0</string>
89 <key>CFBundleDevelopmentRegion</key>
90 <string>en</string>
91 <key>UILaunchStoryboardName</key>
92 <string>LaunchScreen</string>
93 <key>UISupportedInterfaceOrientations</key>
94 <array>
95 <string>UIInterfaceOrientationPortrait</string>
96 <string>UIInterfaceOrientationPortraitUpsideDown</string>
97 <string>UIInterfaceOrientationLandscapeLeft</string>
98 <string>UIInterfaceOrientationLandscapeRight</string>
99 </array>
100 <key>UIRequiresFullScreen</key>
101 <false/>
102 <key>CFBundleExecutable</key>
103 <string>test</string>
104</dict>
105</plist>"#;
106
107 #[test]
108 fn test_plist_equality() {
109 let dir = tempfile::tempdir().unwrap();
110 let properties = InfoPlist {
111 localization: Localization {
112 bundle_development_region: Some("en".to_owned()),
113 ..Default::default()
114 },
115 launch: Launch {
116 bundle_executable: Some("test".to_owned()),
117 ..Default::default()
118 },
119 identification: Identification {
120 bundle_identifier: "com.test.test-id".to_owned(),
121 ..Default::default()
122 },
123 bundle_version: BundleVersion {
124 bundle_version: Some("1".to_owned()),
125 bundle_info_dictionary_version: Some("1.0".to_owned()),
126 bundle_short_version_string: Some("1.0".to_owned()),
127 ..Default::default()
128 },
129 naming: Naming {
130 bundle_name: Some("Test".to_owned()),
131 ..Default::default()
132 },
133 categorization: Categorization {
134 bundle_package_type: Some("APPL".to_owned()),
135 application_category_type: Some(AppCategoryType::Business),
136 },
137 launch_interface: LaunchInterface {
138 launch_storyboard_name: Some("LaunchScreen".to_owned()),
139 ..Default::default()
140 },
141 styling: Styling {
142 requires_full_screen: Some(false),
143 ..Default::default()
144 },
145 orientation: Orientation {
146 supported_interface_orientations: Some(vec![
147 InterfaceOrientation::Portrait,
148 InterfaceOrientation::PortraitUpsideDown,
149 InterfaceOrientation::LandscapeLeft,
150 InterfaceOrientation::LandscapeRight,
151 ]),
152 ..Default::default()
153 },
154 ..Default::default()
155 };
156 let file_path = dir.path().join(PLIST_FILE_NAME);
158 let file = std::fs::File::create(file_path).unwrap();
159 plist::to_writer_xml(file, &properties).unwrap();
161 let file_path = dir.path().join(PLIST_FILE_NAME);
163 let result = std::fs::read_to_string(&file_path).unwrap();
164 assert_eq!(result, PLIST_TEST_EXAMPLE.replace(" ", "\t"));
165 let got_props: InfoPlist = plist::from_bytes(result.as_bytes()).unwrap();
167 assert_eq!(properties, got_props);
168 }
169}