@@ -12,6 +12,7 @@ use log::{error, info};
1212#[ cfg( feature = "sqlite" ) ]
1313use super :: SqliteDictionary ;
1414use super :: { Dictionary , TrieBuf , uhash} ;
15+ use crate :: exn:: { Exn , ResultExt } ;
1516use crate :: {
1617 dictionary:: DictionaryUsage ,
1718 editor:: { AbbrevTable , SymbolSelector } ,
@@ -33,27 +34,6 @@ pub struct AssetLoader {
3334 search_path : Option < String > ,
3435}
3536
36- /// Errors during loading system or user dictionaries.
37- #[ derive( Debug ) ]
38- pub enum LoadDictionaryError {
39- /// Cannot find any system or user dictionary.
40- NotFound ,
41- /// IO Error.
42- IoError ( io:: Error ) ,
43- }
44-
45- impl Display for LoadDictionaryError {
46- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
47- write ! ( f, "Unable to load system dictionary: {self:?}" )
48- }
49- }
50-
51- impl Error for LoadDictionaryError { }
52-
53- fn io_err ( err : io:: Error ) -> LoadDictionaryError {
54- LoadDictionaryError :: IoError ( err)
55- }
56-
5737impl AssetLoader {
5838 /// Creates a new dictionary loader.
5939 pub fn new ( ) -> AssetLoader {
@@ -112,29 +92,33 @@ impl AssetLoader {
11292 }
11393 /// Loads the abbrev table.
11494 pub fn load_abbrev ( & self ) -> Result < AbbrevTable , LoadDictionaryError > {
95+ let error = || LoadDictionaryError :: new ( "failed to load abbrev table" ) ;
96+ let not_found = || error ( ) . with_source ( io:: Error :: from ( io:: ErrorKind :: NotFound ) ) ;
11597 let search_path = if let Some ( path) = & self . search_path {
11698 path. to_owned ( )
11799 } else {
118100 search_path_from_env_var ( )
119101 } ;
120- let parent_path = find_path_by_files ( & search_path , & [ ABBREV_FILE_NAME ] )
121- . ok_or ( LoadDictionaryError :: NotFound ) ?;
102+ let parent_path =
103+ find_path_by_files ( & search_path , & [ ABBREV_FILE_NAME ] ) . or_raise ( not_found ) ?;
122104 let abbrev_path = parent_path. join ( ABBREV_FILE_NAME ) ;
123105 info ! ( "Loading {ABBREV_FILE_NAME}" ) ;
124- AbbrevTable :: open ( abbrev_path) . map_err ( io_err )
106+ AbbrevTable :: open ( abbrev_path) . or_raise ( error )
125107 }
126108 /// Loads the symbol table.
127109 pub fn load_symbol_selector ( & self ) -> Result < SymbolSelector , LoadDictionaryError > {
110+ let error = || LoadDictionaryError :: new ( "failed to load symbol table" ) ;
111+ let not_found = || error ( ) . with_source ( io:: Error :: from ( io:: ErrorKind :: NotFound ) ) ;
128112 let search_path = if let Some ( path) = & self . search_path {
129113 path. to_owned ( )
130114 } else {
131115 search_path_from_env_var ( )
132116 } ;
133- let parent_path = find_path_by_files ( & search_path , & [ SYMBOLS_FILE_NAME ] )
134- . ok_or ( LoadDictionaryError :: NotFound ) ?;
117+ let parent_path =
118+ find_path_by_files ( & search_path , & [ SYMBOLS_FILE_NAME ] ) . or_raise ( not_found ) ?;
135119 let symbol_path = parent_path. join ( SYMBOLS_FILE_NAME ) ;
136120 info ! ( "Loading {SYMBOLS_FILE_NAME}" ) ;
137- SymbolSelector :: open ( symbol_path) . map_err ( io_err )
121+ SymbolSelector :: open ( symbol_path) . or_raise ( error )
138122 }
139123}
140124
@@ -171,34 +155,39 @@ impl UserDictionaryManager {
171155 ///
172156 /// If no user dictionary were found, a new dictionary will be created at
173157 /// the default path.
174- pub fn init ( & self ) -> io:: Result < Box < dyn Dictionary > > {
158+ pub fn init ( & self ) -> Result < Box < dyn Dictionary > , LoadDictionaryError > {
159+ let error = || LoadDictionaryError :: new ( "failed to init user dictionary" ) ;
160+ let not_found = || error ( ) . with_source ( io:: Error :: from ( io:: ErrorKind :: NotFound ) ) ;
175161 let mut loader = SingleDictionaryLoader :: new ( ) ;
176162 loader. migrate_sqlite ( true ) ;
177163 let data_path = self
178164 . data_path
179165 . clone ( )
180166 . or_else ( userphrase_path)
181- . ok_or ( io :: Error :: from ( io :: ErrorKind :: NotFound ) ) ?;
167+ . or_raise ( not_found ) ?;
182168 if data_path. ends_with ( UD_MEM_FILE_NAME ) {
183169 return Ok ( Self :: in_memory ( ) ) ;
184170 }
185171 if data_path. exists ( ) {
186172 info ! ( "Use existing user dictionary {}" , data_path. display( ) ) ;
187- return loader. guess_format_and_load ( & data_path) . map ( |mut dict| {
188- dict. set_usage ( DictionaryUsage :: User ) ;
189- dict
190- } ) ;
173+ return loader
174+ . guess_format_and_load ( & data_path)
175+ . map ( |mut dict| {
176+ dict. set_usage ( DictionaryUsage :: User ) ;
177+ dict
178+ } )
179+ . or_raise ( error) ;
191180 }
192181 let userdata_dir = data_path. parent ( ) . expect ( "path should contain a filename" ) ;
193182 if !userdata_dir. exists ( ) {
194183 info ! ( "Creating userdata_dir: {}" , userdata_dir. display( ) ) ;
195- fs:: create_dir_all ( userdata_dir) ?;
184+ fs:: create_dir_all ( userdata_dir) . or_raise ( error ) ?;
196185 }
197186 info ! (
198187 "Creating a fresh user dictionary at {}" ,
199188 data_path. display( )
200189 ) ;
201- let mut fresh_dict = loader. guess_format_and_load ( & data_path) ?;
190+ let mut fresh_dict = loader. guess_format_and_load ( & data_path) . or_raise ( error ) ?;
202191
203192 let user_dict_path = userdata_dir. join ( UD_SQLITE_FILE_NAME ) ;
204193 if cfg ! ( feature = "sqlite" ) && user_dict_path. exists ( ) {
@@ -208,18 +197,15 @@ impl UserDictionaryManager {
208197 "Importing existing sqlite dictionary at {}" ,
209198 user_dict_path. display( )
210199 ) ;
211- let dict = SqliteDictionary :: open ( user_dict_path)
212- . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: Other , Box :: new ( e) ) ) ?;
200+ let dict = SqliteDictionary :: open ( user_dict_path) . or_raise ( error) ?;
213201 for ( syllables, phrase) in dict. entries ( ) {
214202 let freq = phrase. freq ( ) ;
215203 let last_used = phrase. last_used ( ) . unwrap_or_default ( ) ;
216204 fresh_dict
217205 . update_phrase ( & syllables, phrase, freq, last_used)
218- . map_err ( |e| io :: Error :: new ( io :: ErrorKind :: Other , Box :: new ( e ) ) ) ?;
206+ . or_raise ( error ) ?;
219207 }
220- fresh_dict
221- . flush ( )
222- . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: Other , Box :: new ( e) ) ) ?;
208+ fresh_dict. flush ( ) . or_raise ( error) ?;
223209 }
224210 } else {
225211 let uhash_path = userdata_dir. join ( UD_UHASH_FILE_NAME ) ;
@@ -228,7 +214,7 @@ impl UserDictionaryManager {
228214 "Importing existing uhash dictionary at {}" ,
229215 user_dict_path. display( )
230216 ) ;
231- let mut input = File :: open ( uhash_path) ?;
217+ let mut input = File :: open ( uhash_path) . or_raise ( error ) ?;
232218 if let Ok ( phrases) = uhash:: try_load_bin ( & input) . or_else ( |_| {
233219 input. rewind ( ) ?;
234220 uhash:: try_load_text ( & input)
@@ -238,11 +224,9 @@ impl UserDictionaryManager {
238224 let last_used = phrase. last_used ( ) . unwrap_or_default ( ) ;
239225 fresh_dict
240226 . update_phrase ( & syllables, phrase, freq, last_used)
241- . map_err ( |e| io :: Error :: other ( Box :: new ( e ) ) ) ?;
227+ . or_raise ( error ) ?;
242228 }
243- fresh_dict
244- . flush ( )
245- . map_err ( |e| io:: Error :: other ( Box :: new ( e) ) ) ?;
229+ fresh_dict. flush ( ) . or_raise ( error) ?;
246230 }
247231 }
248232 }
@@ -254,20 +238,24 @@ impl UserDictionaryManager {
254238 ///
255239 /// If no user exclusion dictionary were found, a new dictionary
256240 /// will be created at the default path.
257- pub fn init_deleted ( & self ) -> io:: Result < Box < dyn Dictionary > > {
241+ pub fn init_deleted ( & self ) -> Result < Box < dyn Dictionary > , LoadDictionaryError > {
242+ let error = || LoadDictionaryError :: new ( "failed to init user exclusion dictionary" ) ;
243+ let not_found = || error ( ) . with_source ( io:: Error :: from ( io:: ErrorKind :: NotFound ) ) ;
258244 let loader = SingleDictionaryLoader :: new ( ) ;
259245 let data_path = self
260246 . data_path
261247 . clone ( )
262248 . or_else ( userphrase_path)
263- . ok_or ( io :: Error :: from ( io :: ErrorKind :: NotFound ) ) ?;
249+ . or_raise ( not_found ) ?;
264250 let userdata_dir = data_path. parent ( ) . expect ( "path should contain a filename" ) ;
265251 if !userdata_dir. exists ( ) {
266252 info ! ( "Creating userdata_dir: {}" , userdata_dir. display( ) ) ;
267- fs:: create_dir_all ( & userdata_dir) ?;
253+ fs:: create_dir_all ( & userdata_dir) . or_raise ( error ) ?;
268254 }
269255 let exclude_dict_path = userdata_dir. join ( "chewing-deleted.dat" ) ;
270- Ok ( loader. guess_format_and_load ( & exclude_dict_path) ?)
256+ loader
257+ . guess_format_and_load ( & exclude_dict_path)
258+ . or_raise ( error)
271259 }
272260 /// Load a in-memory user dictionary.
273261 pub fn in_memory ( ) -> Box < dyn Dictionary > {
@@ -290,12 +278,16 @@ impl SingleDictionaryLoader {
290278 pub fn migrate_sqlite ( & mut self , migrate : bool ) {
291279 self . migrate_sqlite = migrate;
292280 }
293- pub fn guess_format_and_load ( & self , dict_path : & PathBuf ) -> io:: Result < Box < dyn Dictionary > > {
281+ pub fn guess_format_and_load (
282+ & self ,
283+ dict_path : & PathBuf ,
284+ ) -> Result < Box < dyn Dictionary > , LoadDictionaryError > {
285+ let error = || LoadDictionaryError :: new ( "failed to parse and load dictionary" ) ;
294286 info ! ( "Loading dictionary {}" , dict_path. display( ) ) ;
295287 if self . migrate_sqlite && dict_path. is_file ( ) {
296- let metadata = dict_path. metadata ( ) ?;
288+ let metadata = dict_path. metadata ( ) . or_raise ( error ) ?;
297289 if metadata. permissions ( ) . readonly ( ) {
298- return Err ( io:: Error :: from ( io:: ErrorKind :: PermissionDenied ) ) ;
290+ return Err ( error ( ) . with_source ( io:: Error :: from ( io:: ErrorKind :: PermissionDenied ) ) ) ;
299291 }
300292 }
301293
@@ -306,23 +298,47 @@ impl SingleDictionaryLoader {
306298 if self . migrate_sqlite {
307299 SqliteDictionary :: open ( dict_path)
308300 . map ( |dict| Box :: new ( dict) as Box < dyn Dictionary > )
309- . map_err ( |e| io :: Error :: new ( io :: ErrorKind :: InvalidData , Box :: new ( e ) ) )
301+ . or_raise ( error )
310302 } else {
311303 SqliteDictionary :: open_readonly ( dict_path)
312304 . map ( |dict| Box :: new ( dict) as Box < dyn Dictionary > )
313- . map_err ( |e| io :: Error :: new ( io :: ErrorKind :: InvalidData , Box :: new ( e ) ) )
305+ . or_raise ( error )
314306 }
315307 }
316308 #[ cfg( not( feature = "sqlite" ) ) ]
317309 {
318- Err ( io:: Error :: from ( io:: ErrorKind :: Unsupported ) )
310+ Err ( error ( ) . with_source ( io:: Error :: from ( io:: ErrorKind :: Unsupported ) ) )
319311 }
320312 } else if ext. eq_ignore_ascii_case ( "dat" ) {
321313 TrieBuf :: open ( dict_path)
322314 . map ( |dict| Box :: new ( dict) as Box < dyn Dictionary > )
323- . map_err ( |e| io :: Error :: new ( io :: ErrorKind :: InvalidData , Box :: new ( e ) ) )
315+ . or_raise ( error )
324316 } else {
325- Err ( io :: Error :: from ( io :: ErrorKind :: Other ) )
317+ Err ( error ( ) )
326318 }
327319 }
328320}
321+
322+ /// Errors during loading system or user dictionaries.
323+ #[ derive( Debug ) ]
324+ pub struct LoadDictionaryError {
325+ msg : String ,
326+ source : Option < Box < dyn Error + Send + Sync + ' static > > ,
327+ }
328+
329+ impl LoadDictionaryError {
330+ fn new ( msg : & str ) -> LoadDictionaryError {
331+ LoadDictionaryError {
332+ msg : msg. to_string ( ) ,
333+ source : None ,
334+ }
335+ }
336+ }
337+
338+ impl Display for LoadDictionaryError {
339+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
340+ f. write_str ( & self . msg )
341+ }
342+ }
343+
344+ impl_exn ! ( LoadDictionaryError ) ;
0 commit comments