@@ -25,11 +25,11 @@ pub use sync::ReadLimiter;
25
25
#[ cfg( feature = "sync_reader" ) ]
26
26
mod sync {
27
27
use crate :: { Error , Result } ;
28
- use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
28
+ use core:: sync:: atomic:: { AtomicUsize , AtomicBool , Ordering } ;
29
29
30
30
pub struct ReadLimiter {
31
- pub limit : usize ,
32
- pub read : AtomicUsize ,
31
+ pub limit : AtomicUsize ,
32
+ pub limit_reached : AtomicBool ,
33
33
}
34
34
35
35
impl ReadLimiter {
@@ -39,21 +39,27 @@ mod sync {
39
39
}
40
40
41
41
ReadLimiter {
42
- limit : limit as usize ,
43
- read : AtomicUsize :: new ( 0 ) ,
42
+ limit : AtomicUsize :: new ( limit as usize ) ,
43
+ limit_reached : AtomicBool :: new ( false ) ,
44
44
}
45
45
}
46
46
47
47
#[ inline]
48
48
pub fn can_read ( & self , amount : usize ) -> Result < ( ) > {
49
- let read = self . read . load ( Ordering :: Relaxed ) + amount;
49
+ let limit_reached = self . limit_reached . load ( Ordering :: Relaxed ) ;
50
+ if limit_reached {
51
+ return Err ( Error :: failed ( format ! ( "read limit exceeded" ) ) ) ;
52
+ }
50
53
51
- if read > self . limit {
52
- Err ( Error :: failed ( format ! ( "read limit exceeded" ) ) )
53
- } else {
54
- self . read . fetch_add ( amount, Ordering :: Relaxed ) ;
55
- Ok ( ( ) )
54
+ let prev_limit = self . limit . fetch_sub ( amount, Ordering :: Relaxed ) ;
55
+ if prev_limit == amount {
56
+ self . limit_reached . store ( true , Ordering :: Relaxed ) ;
57
+ } else if prev_limit < amount {
58
+ self . limit_reached . store ( true , Ordering :: Relaxed ) ;
59
+ return Err ( Error :: failed ( format ! ( "read limit exceeded" ) ) ) ;
56
60
}
61
+
62
+ Ok ( ( ) )
57
63
}
58
64
}
59
65
}
@@ -63,8 +69,8 @@ pub use unsync::ReadLimiter;
63
69
64
70
#[ cfg( not( feature = "sync_reader" ) ) ]
65
71
mod unsync {
66
- use core:: cell:: Cell ;
67
72
use crate :: { Error , Result } ;
73
+ use core:: cell:: Cell ;
68
74
69
75
pub struct ReadLimiter {
70
76
pub limit : Cell < u64 > ,
0 commit comments