1
1
use super :: { ErrorReport , Event , ParallelReporter , ProgressReport , Reporter , Size } ;
2
- use pipe_trait :: Pipe ;
2
+ use progress_report_state :: ProgressReportState ;
3
3
use std:: {
4
4
any:: Any ,
5
- sync:: { Arc , RwLock } ,
5
+ marker:: PhantomData ,
6
+ ops:: ControlFlow ,
7
+ sync:: { atomic:: Ordering :: Relaxed , Arc } ,
6
8
thread:: { sleep, spawn, JoinHandle } ,
7
9
time:: Duration ,
8
10
} ;
@@ -15,19 +17,23 @@ pub struct ProgressAndErrorReporter<Data, ReportError>
15
17
where
16
18
Data : Size + Send + Sync ,
17
19
ReportError : Fn ( ErrorReport ) + Sync ,
20
+ u64 : Into < Data > ,
18
21
{
19
22
/// Progress information.
20
- progress : Arc < RwLock < Option < ProgressReport < Data > > > > ,
23
+ progress : Arc < ProgressReportState > ,
21
24
/// Report encountered error.
22
25
report_error : ReportError ,
23
26
/// Join handle of progress reporting thread.
24
27
progress_reporter_handle : JoinHandle < ( ) > ,
28
+ /// Keep generic parameters.
29
+ _phantom : PhantomData < Data > ,
25
30
}
26
31
27
32
impl < Data , ReportError > ProgressAndErrorReporter < Data , ReportError >
28
33
where
29
34
Data : Size + Send + Sync ,
30
35
ReportError : Fn ( ErrorReport ) + Sync ,
36
+ u64 : Into < Data > ,
31
37
{
32
38
/// Create a new [`ProgressAndErrorReporter`] from a report function.
33
39
pub fn new < ReportProgress > (
@@ -39,41 +45,36 @@ where
39
45
ProgressReport < Data > : Default + ' static ,
40
46
ReportProgress : Fn ( ProgressReport < Data > ) + Send + Sync + ' static ,
41
47
{
42
- let progress = ProgressReport :: default ( )
43
- . pipe ( Some )
44
- . pipe ( RwLock :: new)
45
- . pipe ( Arc :: new) ;
48
+ let progress = Arc :: new ( ProgressReportState :: default ( ) ) ;
46
49
let progress_thread = progress. clone ( ) ;
47
50
let progress_reporter_handle = spawn ( move || loop {
48
51
sleep ( progress_report_interval) ;
49
- if let Ok ( progress) = progress_thread. read ( ) . as_deref ( ) {
50
- if let Some ( progress) = * progress {
51
- report_progress ( progress) ;
52
- } else {
53
- break ;
54
- }
55
- }
52
+ match progress_thread. to_progress_report ( ) {
53
+ ControlFlow :: Continue ( progress) => report_progress ( progress) ,
54
+ ControlFlow :: Break ( ( ) ) => break ,
55
+ } ;
56
56
} ) ;
57
57
ProgressAndErrorReporter {
58
58
progress,
59
59
report_error,
60
60
progress_reporter_handle,
61
+ _phantom : PhantomData ,
61
62
}
62
63
}
63
64
64
65
/// Stop the thread that reports progress.
65
66
///
66
67
/// This function would be automatically invoked once the value is [dropped](Drop).
67
68
pub fn stop_progress_reporter ( & self ) {
68
- let mut progress = self . progress . write ( ) . expect ( "lock progress to stop" ) ;
69
- * progress = None ;
69
+ self . progress . stopped . store ( true , Relaxed ) ;
70
70
}
71
71
}
72
72
73
73
impl < Data , ReportError > Reporter < Data > for ProgressAndErrorReporter < Data , ReportError >
74
74
where
75
- Data : Size + Send + Sync ,
75
+ Data : Size + Into < u64 > + Send + Sync ,
76
76
ReportError : Fn ( ErrorReport ) + Sync ,
77
+ u64 : Into < Data > ,
77
78
{
78
79
fn report ( & self , event : Event < Data > ) {
79
80
use Event :: * ;
@@ -82,38 +83,35 @@ where
82
83
report_error,
83
84
..
84
85
} = self ;
85
- macro_rules! handle_field {
86
- ( $( $field: ident $operator: tt $addend: expr; ) +) => {
87
- if let Some ( progress) = progress. write( ) . ok( ) . as_mut( ) . and_then( |x| x. as_mut( ) ) {
88
- $( progress. $field $operator $addend; ) +
89
- }
86
+ macro_rules! bump {
87
+ ( $field: ident += $delta: expr) => {
88
+ progress. $field. fetch_add( $delta, Relaxed )
90
89
} ;
91
90
}
92
91
match event {
93
92
ReceiveData ( data) => {
94
- handle_field ! {
95
- items += 1 ;
96
- total += data;
97
- }
93
+ bump ! ( items += 1 ) ;
94
+ bump ! ( total += data. into( ) ) ;
98
95
}
99
96
EncounterError ( error_report) => {
100
97
report_error ( error_report) ;
101
- handle_field ! {
102
- errors += 1 ;
103
- }
98
+ bump ! ( errors += 1 ) ;
104
99
}
105
100
}
106
101
}
107
102
}
108
103
109
104
impl < Data , ReportError > ParallelReporter < Data > for ProgressAndErrorReporter < Data , ReportError >
110
105
where
111
- Data : Size + Send + Sync ,
106
+ Data : Size + Into < u64 > + Send + Sync ,
112
107
ReportError : Fn ( ErrorReport ) + Sync ,
108
+ u64 : Into < Data > ,
113
109
{
114
110
type DestructionError = Box < dyn Any + Send + ' static > ;
115
111
fn destroy ( self ) -> Result < ( ) , Self :: DestructionError > {
116
112
self . stop_progress_reporter ( ) ;
117
113
self . progress_reporter_handle . join ( )
118
114
}
119
115
}
116
+
117
+ mod progress_report_state;
0 commit comments