@@ -16,10 +16,14 @@ use std::ffi::OsStr;
16
16
use std:: fs:: File ;
17
17
use std:: path:: PathBuf ;
18
18
use std:: sync:: atomic:: { AtomicBool , Ordering } ;
19
+ use std:: result;
20
+ use std:: fmt;
19
21
20
22
use app_dirs:: { app_dir, app_root, get_app_root, sanitized, AppDataType } ;
21
23
use toml;
22
24
25
+ use serde:: de:: { self , Deserialize , Deserializer , Visitor , MapAccess } ;
26
+
23
27
use errors:: { ErrorKind , Result } ;
24
28
use io:: itarbundle:: { HttpITarIoFactory , ITarBundle } ;
25
29
use io:: local_cache:: LocalCache ;
@@ -47,16 +51,157 @@ url = "https://archive.org/services/purl/net/pkgwpub/tectonic-default"
47
51
"# ;
48
52
49
53
50
- #[ derive( Deserialize ) ]
51
54
pub struct PersistentConfig {
52
55
default_bundles : Vec < BundleInfo > ,
53
56
}
54
57
55
- #[ derive( Deserialize ) ]
58
+ // Manual implementation of Deserialize because serde_derive does not work with musl
59
+ // See https://github.com/rust-lang/rust/issues/40174
60
+ // Implementation based on https://serde.rs/deserialize-struct.html
61
+ impl < ' de > Deserialize < ' de > for PersistentConfig {
62
+ fn deserialize < D > ( deserializer : D ) -> result:: Result < Self , D :: Error >
63
+ where
64
+ D : Deserializer < ' de > ,
65
+ {
66
+ enum Field { DefaultBundles } ;
67
+
68
+ impl < ' de > Deserialize < ' de > for Field {
69
+ fn deserialize < D > ( deserializer : D ) -> result:: Result < Field , D :: Error >
70
+ where
71
+ D : Deserializer < ' de > ,
72
+ {
73
+ struct FieldVisitor ;
74
+
75
+ impl < ' de > Visitor < ' de > for FieldVisitor {
76
+ type Value = Field ;
77
+
78
+ fn expecting ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
79
+ formatter. write_str ( "`default_bundles`" )
80
+ }
81
+
82
+ fn visit_str < E > ( self , value : & str ) -> result:: Result < Field , E >
83
+ where
84
+ E : de:: Error ,
85
+ {
86
+ match value {
87
+ "default_bundles" => Ok ( Field :: DefaultBundles ) ,
88
+ _ => Err ( de:: Error :: unknown_field ( value, FIELDS ) ) ,
89
+ }
90
+ }
91
+ }
92
+
93
+ deserializer. deserialize_identifier ( FieldVisitor )
94
+ }
95
+ }
96
+
97
+ struct PersistentConfigVisitor ;
98
+
99
+ impl < ' de > Visitor < ' de > for PersistentConfigVisitor {
100
+ type Value = PersistentConfig ;
101
+
102
+ fn expecting ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
103
+ formatter. write_str ( "struct PersistentConfig" )
104
+ }
105
+
106
+ fn visit_map < V > ( self , mut map : V ) -> result:: Result < PersistentConfig , V :: Error >
107
+ where
108
+ V : MapAccess < ' de > ,
109
+ {
110
+ let mut default_bundles = None ;
111
+ while let Some ( key) = map. next_key ( ) ? {
112
+ match key {
113
+ Field :: DefaultBundles => {
114
+ if default_bundles. is_some ( ) {
115
+ return Err ( de:: Error :: duplicate_field ( "default_bundles" ) ) ;
116
+ }
117
+ default_bundles = Some ( map. next_value ( ) ?) ;
118
+ }
119
+ }
120
+ }
121
+ let default_bundles = default_bundles. ok_or_else ( || de:: Error :: missing_field ( "default_bundles" ) ) ?;
122
+ Ok ( PersistentConfig { default_bundles } )
123
+ }
124
+ }
125
+
126
+ const FIELDS : & ' static [ & ' static str ] = & [ "default_bundles" ] ;
127
+ deserializer. deserialize_struct ( "PersistentConfig" , FIELDS , PersistentConfigVisitor )
128
+ }
129
+ }
130
+
56
131
pub struct BundleInfo {
57
132
url : String ,
58
133
}
59
134
135
+ impl < ' de > Deserialize < ' de > for BundleInfo {
136
+ fn deserialize < D > ( deserializer : D ) -> result:: Result < Self , D :: Error >
137
+ where
138
+ D : Deserializer < ' de > ,
139
+ {
140
+ enum Field { Url } ;
141
+
142
+ impl < ' de > Deserialize < ' de > for Field {
143
+ fn deserialize < D > ( deserializer : D ) -> result:: Result < Field , D :: Error >
144
+ where
145
+ D : Deserializer < ' de > ,
146
+ {
147
+ struct FieldVisitor ;
148
+
149
+ impl < ' de > Visitor < ' de > for FieldVisitor {
150
+ type Value = Field ;
151
+
152
+ fn expecting ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
153
+ formatter. write_str ( "`url`" )
154
+ }
155
+
156
+ fn visit_str < E > ( self , value : & str ) -> result:: Result < Field , E >
157
+ where
158
+ E : de:: Error ,
159
+ {
160
+ match value {
161
+ "url" => Ok ( Field :: Url ) ,
162
+ _ => Err ( de:: Error :: unknown_field ( value, FIELDS ) ) ,
163
+ }
164
+ }
165
+ }
166
+
167
+ deserializer. deserialize_identifier ( FieldVisitor )
168
+ }
169
+ }
170
+
171
+ struct BundleInfoVisitor ;
172
+
173
+ impl < ' de > Visitor < ' de > for BundleInfoVisitor {
174
+ type Value = BundleInfo ;
175
+
176
+ fn expecting ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
177
+ formatter. write_str ( "struct BundleInfo" )
178
+ }
179
+
180
+ fn visit_map < V > ( self , mut map : V ) -> result:: Result < BundleInfo , V :: Error >
181
+ where
182
+ V : MapAccess < ' de > ,
183
+ {
184
+ let mut url = None ;
185
+ while let Some ( key) = map. next_key ( ) ? {
186
+ match key {
187
+ Field :: Url => {
188
+ if url. is_some ( ) {
189
+ return Err ( de:: Error :: duplicate_field ( "url" ) ) ;
190
+ }
191
+ url = Some ( map. next_value ( ) ?) ;
192
+ }
193
+ }
194
+ }
195
+ let url = url. ok_or_else ( || de:: Error :: missing_field ( "url" ) ) ?;
196
+ Ok ( BundleInfo { url } )
197
+ }
198
+ }
199
+
200
+ const FIELDS : & ' static [ & ' static str ] = & [ "url" ] ;
201
+ deserializer. deserialize_struct ( "BundleInfo" , FIELDS , BundleInfoVisitor )
202
+ }
203
+ }
204
+
60
205
impl PersistentConfig {
61
206
pub fn open ( auto_create_config_file : bool ) -> Result < PersistentConfig > {
62
207
let mut cfg_path = if auto_create_config_file {
0 commit comments