loopmini 0.2.1__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -60,6 +60,12 @@ jobs:
60
60
  contents: write
61
61
  steps:
62
62
  - uses: actions/checkout@v7
63
+ - uses: dtolnay/rust-toolchain@stable
64
+ - id: crates-auth
65
+ uses: rust-lang/crates-io-auth-action@v1
66
+ - run: cargo publish
67
+ env:
68
+ CARGO_REGISTRY_TOKEN: ${{ steps.crates-auth.outputs.token }}
63
69
  - uses: actions/download-artifact@v8
64
70
  with:
65
71
  path: dist
@@ -65,7 +65,7 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
65
65
 
66
66
  [[package]]
67
67
  name = "loopmini"
68
- version = "0.2.1"
68
+ version = "0.2.2"
69
69
  dependencies = [
70
70
  "polling",
71
71
  "pyo3",
@@ -1,11 +1,10 @@
1
1
  [package]
2
2
  name = "loopmini"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  edition = "2021"
5
5
  license = "Apache-2.0"
6
6
  description = "Rust-backed asyncio event loop"
7
7
  repository = "https://github.com/AnswerDotAI/loopmini"
8
- publish = false
9
8
  readme = "README.md"
10
9
 
11
10
  [lib]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: loopmini
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Requires-Dist: fastship>=0.0.11 ; extra == 'dev'
@@ -44,14 +44,22 @@ impl PyReactor {
44
44
  // An injected async exception (e.g. KeyboardInterrupt) can surface at either
45
45
  // Python call; only a handle whose _run began may be dropped without requeue.
46
46
  let cancelled = h.bind(py).getattr(intern!(py, "_cancelled")).and_then(|v| v.extract::<bool>());
47
- match cancelled { Err(e) => { self.core.requeue_front(std::iter::once(h).chain(it)); return Err(e); } Ok(true) => continue, Ok(false) => {} }
47
+ match cancelled {
48
+ Err(e) => {
49
+ self.core.requeue_front(std::iter::once(h).chain(it));
50
+ return Err(e);
51
+ }
52
+ Ok(true) => continue,
53
+ Ok(false) => {}
54
+ }
48
55
  if let Err(e) = h.bind(py).call_method0(intern!(py, "_run")) {
49
56
  // An injected exception surfacing at `_run`'s entry leaves a single-frame
50
57
  // traceback: the callback never ran, so requeue the handle - dropping it
51
58
  // would lose e.g. a task wakeup and orphan the task. A deeper traceback
52
59
  // means the callback began, so the handle is consumed (CPython semantics).
53
60
  let entry_only = e.traceback(py).map_or(true, |tb| tb.getattr("tb_next").ok().is_none_or(|n| n.is_none()));
54
- if entry_only { self.core.requeue_front(std::iter::once(h).chain(it)) } else { self.core.requeue_front(it) }
61
+ if entry_only { self.core.requeue_front(std::iter::once(h).chain(it)) }
62
+ else { self.core.requeue_front(it) }
55
63
  return Err(e);
56
64
  }
57
65
  }
@@ -79,7 +79,8 @@ impl<H: Clone> Reactor<H> {
79
79
  let mut inner = self.inner.lock().unwrap();
80
80
  let fresh = !inner.fds.contains_key(&fd);
81
81
  let e = inner.fds.entry(fd).or_default();
82
- if write { e.writer = Some(h) } else { e.reader = Some(h) }
82
+ if write { e.writer = Some(h) }
83
+ else { e.reader = Some(h) }
83
84
  let ev = interest(fd, e);
84
85
  if fresh { unsafe { self.poller.add(fd as i32, ev) } } else { self.poller.modify(borrowed(fd), ev) }
85
86
  }
@@ -90,7 +91,11 @@ impl<H: Clone> Reactor<H> {
90
91
  let had = if write { e.writer.take().is_some() } else { e.reader.take().is_some() };
91
92
  let empty = e.reader.is_none() && e.writer.is_none();
92
93
  let ev = interest(fd, e);
93
- if empty { inner.fds.remove(&fd); let _ = self.poller.delete(borrowed(fd)); } else { self.poller.modify(borrowed(fd), ev)? }
94
+ if empty {
95
+ inner.fds.remove(&fd);
96
+ let _ = self.poller.delete(borrowed(fd));
97
+ }
98
+ else { self.poller.modify(borrowed(fd), ev)? }
94
99
  Ok(had)
95
100
  }
96
101
 
@@ -122,11 +127,17 @@ impl<H: Clone> Reactor<H> {
122
127
  /// cross-thread handles, and say how long the driver may block in `poll`.
123
128
  pub fn next_timeout(&self) -> ControlFlow<(), Option<Duration>> {
124
129
  let mut inner = self.inner.lock().unwrap();
125
- if inner.stop { inner.stop = false; return ControlFlow::Break(()) }
130
+ if inner.stop {
131
+ inner.stop = false;
132
+ return ControlFlow::Break(());
133
+ }
126
134
  let Inner { ready, timers, .. } = &mut *inner;
127
135
  self.drain_tsq(ready);
128
136
  let now = self.now_us();
129
- while timers.first_key_value().is_some_and(|((when, _), _)| *when <= now) { let (_, h) = timers.pop_first().unwrap(); ready.push_back(h); }
137
+ while timers.first_key_value().is_some_and(|((when, _), _)| *when <= now) {
138
+ let (_, h) = timers.pop_first().unwrap();
139
+ ready.push_back(h);
140
+ }
130
141
  // Clamped like CPython's MAXIMUM_SELECT_TIMEOUT: a sleep(inf) timer saturates
131
142
  // to u64::MAX, and a pure-Rust consumer blocking in `poll` would hand that
132
143
  // timespec to kqueue, which rejects it with EINVAL
@@ -175,7 +186,10 @@ mod tests {
175
186
  fn cross_thread_schedule_wakes_poll() {
176
187
  let reactor = Arc::new(Reactor::new().unwrap());
177
188
  let sender = reactor.clone();
178
- let thread = thread::spawn(move || { thread::sleep(Duration::from_millis(10)); sender.schedule_ts("ready").unwrap(); });
189
+ let thread = thread::spawn(move || {
190
+ thread::sleep(Duration::from_millis(10));
191
+ sender.schedule_ts("ready").unwrap();
192
+ });
179
193
  let events = reactor.poll(None).unwrap();
180
194
  reactor.process(&events);
181
195
  thread.join().unwrap();
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes