@@ -340,13 +340,17 @@ pub unsafe extern "C" fn gifski_set_progress_callback(handle: *const GifskiHandl
340340 Some ( g) => g,
341341 None => return GifskiError :: NULL_ARG ,
342342 } ;
343- let t = g. write_thread . lock ( ) . unwrap ( ) ;
344- if t. 0 {
343+ if g. write_thread . lock ( ) . map_or ( true , |t| t. 0 ) {
345344 eprintln ! ( "tried to set progress callback after writing has already started" ) ;
346345 return GifskiError :: INVALID_STATE ;
347346 }
348- * g. progress . lock ( ) . unwrap ( ) = Some ( ProgressCallback :: new ( cb, user_data) ) ;
349- GifskiError :: OK
347+ match g. progress . lock ( ) {
348+ Ok ( mut progress) => {
349+ * progress = Some ( ProgressCallback :: new ( cb, user_data) ) ;
350+ GifskiError :: OK
351+ } ,
352+ Err ( _) => GifskiError :: THREAD_LOST ,
353+ }
350354}
351355
352356/// Start writing to the `destination`. This has to be called before any frames are added.
@@ -364,7 +368,7 @@ pub unsafe extern "C" fn gifski_set_file_output(handle: *const GifskiHandle, des
364368 Ok ( res) => res,
365369 Err ( err) => return err,
366370 } ;
367- gifski_write_thread_start ( g, file, Some ( path) )
371+ gifski_write_thread_start ( g, file, Some ( path) ) . err ( ) . unwrap_or ( GifskiError :: OK )
368372}
369373
370374
@@ -377,7 +381,7 @@ fn prepare_for_file_writing(g: &GifskiHandleInternal, destination: *const c_char
377381 } else {
378382 return Err ( GifskiError :: INVALID_INPUT ) ;
379383 } ;
380- let t = g. write_thread . lock ( ) . unwrap ( ) ;
384+ let t = g. write_thread . lock ( ) . map_err ( |_| GifskiError :: THREAD_LOST ) ? ;
381385 if t. 0 {
382386 eprintln ! ( "tried to start writing for the second time, after it has already started" ) ;
383387 return Err ( GifskiError :: INVALID_STATE ) ;
@@ -435,24 +439,21 @@ pub unsafe extern "C" fn gifski_set_write_callback(handle: *const GifskiHandle,
435439 None => return GifskiError :: NULL_ARG ,
436440 } ;
437441 let writer = CallbackWriter { cb, user_data } ;
438- gifski_write_thread_start ( g, writer, None )
442+ gifski_write_thread_start ( g, writer, None ) . err ( ) . unwrap_or ( GifskiError :: OK )
439443}
440444
441- fn gifski_write_thread_start < W : ' static + Write + Send > ( g : & GifskiHandleInternal , file : W , path : Option < PathBuf > ) -> GifskiError {
442- let mut t = g. write_thread . lock ( ) . unwrap ( ) ;
445+ fn gifski_write_thread_start < W : ' static + Write + Send > ( g : & GifskiHandleInternal , file : W , path : Option < PathBuf > ) -> Result < ( ) , GifskiError > {
446+ let mut t = g. write_thread . lock ( ) . map_err ( |_| GifskiError :: THREAD_LOST ) ? ;
443447 if t. 0 {
444448 eprintln ! ( "gifski_set_file_output/gifski_set_write_callback has been called already" ) ;
445- return GifskiError :: INVALID_STATE ;
449+ return Err ( GifskiError :: INVALID_STATE ) ;
446450 }
447- let writer = g. writer . lock ( ) . unwrap ( ) . take ( ) ;
448- let mut user_progress = g. progress . lock ( ) . unwrap ( ) . take ( ) ;
451+ let writer = g. writer . lock ( ) . map_err ( |_| GifskiError :: THREAD_LOST ) ? . take ( ) ;
452+ let mut user_progress = g. progress . lock ( ) . map_err ( |_| GifskiError :: THREAD_LOST ) ? . take ( ) ;
449453 let handle = thread:: Builder :: new ( ) . name ( "c-write" . into ( ) ) . spawn ( move || {
450454 if let Some ( writer) = writer {
451- let mut progress: & mut dyn ProgressReporter = & mut NoProgress { } ;
452- if let Some ( cb) = & mut user_progress {
453- progress = & mut * cb;
454- }
455- match writer. write ( file, progress) . into ( ) {
455+ let progress = user_progress. as_mut ( ) . map ( |m| m as & mut dyn ProgressReporter ) ;
456+ match writer. write ( file, progress. unwrap_or ( & mut NoProgress { } ) ) . into ( ) {
456457 res @ ( GifskiError :: OK | GifskiError :: ALREADY_EXISTS ) => res,
457458 err => {
458459 if let Some ( path) = path {
@@ -469,9 +470,9 @@ fn gifski_write_thread_start<W: 'static + Write + Send>(g: &GifskiHandleInterna
469470 match handle {
470471 Ok ( handle) => {
471472 * t = ( true , Some ( handle) ) ;
472- GifskiError :: OK
473+ Ok ( ( ) )
473474 } ,
474- Err ( _) => GifskiError :: THREAD_LOST ,
475+ Err ( _) => Err ( GifskiError :: THREAD_LOST ) ,
475476 }
476477}
477478
@@ -497,14 +498,27 @@ pub unsafe extern "C" fn gifski_finish(g: *const GifskiHandle) -> GifskiError {
497498 }
498499 let g = Arc :: from_raw ( g. cast :: < GifskiHandleInternal > ( ) ) ;
499500
500- // dropping of the collector (if any) completes writing
501- * g. collector . lock ( ) . unwrap ( ) = None ;
501+ match g. collector . lock ( ) {
502+ // dropping of the collector (if any) completes writing
503+ Ok ( mut lock) => * lock = None ,
504+ Err ( _) => {
505+ eprintln ! ( "warning: collector thread crashed" ) ;
506+ } ,
507+ } ;
508+
509+ let thread = match g. write_thread . lock ( ) {
510+ Ok ( mut writer) => writer. 1 . take ( ) ,
511+ Err ( _) => return GifskiError :: THREAD_LOST ,
512+ } ;
502513
503- let thread = g. write_thread . lock ( ) . unwrap ( ) . 1 . take ( ) ;
504514 if let Some ( thread) = thread {
505- thread. join ( ) . unwrap_or ( GifskiError :: THREAD_LOST )
515+ thread. join ( ) . map_err ( |e| {
516+ let msg = e. downcast_ref :: < String > ( ) . map ( |s| s. as_str ( ) )
517+ . or_else ( || e. downcast_ref :: < & str > ( ) . copied ( ) ) . unwrap_or ( "unknown panic" ) ;
518+ eprintln ! ( "writer crashed (this is a bug): {msg}" ) ;
519+ } ) . unwrap_or ( GifskiError :: THREAD_LOST )
506520 } else {
507- eprintln ! ( "gifski_finish called before any output has been set" ) ;
521+ eprintln ! ( "warning: gifski_finish called before any output has been set" ) ;
508522 GifskiError :: OK // this will become INVALID_STATE once sync write support is dropped
509523 }
510524}
0 commit comments