Skip to content

Commit 825e02a

Browse files
committed
uh, try rewriting clock timer builder with typestate pattern?
no clue if it works right, but the types work out,
1 parent 905a0c0 commit 825e02a

File tree

1 file changed

+99
-2
lines changed

1 file changed

+99
-2
lines changed

src/clock_timer.rs

+99-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ pub struct Tick {
7474
impl ClockTimer {
7575
/// Gets a [`ClockTimer`] builder
7676
#[inline]
77-
pub fn builder() -> builder::Builder {
78-
builder::Builder::new()
77+
pub fn builder() -> builder2::Builder {
78+
builder2::Builder::new()
7979
}
8080

8181
/// Runs the next tick and returns timing information for it, if this
@@ -306,3 +306,100 @@ pub mod builder {
306306
}
307307
}
308308
}
309+
310+
pub mod builder2 {
311+
use super::*;
312+
313+
pub struct MarkerUninit {
314+
__private: ()
315+
}
316+
317+
pub struct MarkerInit {
318+
__private: ()
319+
}
320+
321+
#[repr(transparent)]
322+
pub struct Builder<
323+
Start = MarkerUninit,
324+
End = MarkerUninit,
325+
Interval = MarkerUninit
326+
> {
327+
inner: BuilderInner,
328+
__marker: PhantomData<(Start, End, Interval)>
329+
}
330+
331+
struct BuilderInner {
332+
start: MaybeUninit<DateTime<Local>>,
333+
end: MaybeUninit<DateTime<Local>>,
334+
interval: MaybeUninit<TimeDelta>
335+
}
336+
337+
impl Builder {
338+
#[expect(clippy::new_without_default, reason = "api design")]
339+
#[inline]
340+
pub fn new() -> Builder {
341+
Builder {
342+
inner: BuilderInner {
343+
start: MaybeUninit::uninit(),
344+
end: MaybeUninit::uninit(),
345+
interval: MaybeUninit::uninit()
346+
},
347+
__marker: PhantomData
348+
}
349+
}
350+
}
351+
352+
impl<End, Interval> Builder<MarkerUninit, End, Interval> {
353+
#[inline]
354+
pub fn with_start_datetime<TZ: TimeZone>(mut self, datetime: DateTime<TZ>) -> Builder<MarkerInit, End, Interval> {
355+
self.inner.start.write(datetime.with_timezone(&Local));
356+
Builder { inner: self.inner, __marker: PhantomData }
357+
}
358+
}
359+
360+
impl<Start, Interval> Builder<Start, MarkerUninit, Interval> {
361+
#[inline]
362+
pub fn with_end_datetime<TZ: TimeZone>(mut self, datetime: DateTime<TZ>) -> Builder<Start, MarkerInit, Interval> {
363+
self.inner.end.write(datetime.with_timezone(&Local));
364+
Builder { inner: self.inner, __marker: PhantomData }
365+
}
366+
}
367+
368+
impl<Interval> Builder<MarkerInit, MarkerUninit, Interval> {
369+
#[inline]
370+
pub fn with_duration(mut self, duration: TimeDelta) -> Builder<MarkerInit, MarkerInit, Interval> {
371+
// SAFETY: enforced by type system (typestate pattern)
372+
let start = unsafe { self.inner.start.assume_init() };
373+
374+
self.inner.end.write(start + duration);
375+
Builder { inner: self.inner, __marker: PhantomData }
376+
}
377+
}
378+
379+
impl<Start, End> Builder<Start, End, MarkerUninit> {
380+
#[inline]
381+
pub fn with_interval(mut self, interval: TimeDelta) -> Builder<Start, End, MarkerInit> {
382+
self.inner.interval.write(interval);
383+
Builder { inner: self.inner, __marker: PhantomData }
384+
}
385+
}
386+
387+
impl Builder<MarkerInit, MarkerInit, MarkerInit> {
388+
#[inline]
389+
pub fn build(self) -> ClockTimer {
390+
// SAFETY: enforced by type system (typestate pattern)
391+
let start = unsafe { self.inner.start.assume_init() };
392+
// SAFETY: enforced by type system (typestate pattern)
393+
let end = unsafe { self.inner.end.assume_init() };
394+
// SAFETY: enforced by type system (typestate pattern)
395+
let interval = unsafe { self.inner.interval.assume_init() };
396+
397+
ClockTimer {
398+
next_tick: start,
399+
interval,
400+
elapsed: TimeDelta::zero(),
401+
remaining: end - start
402+
}
403+
}
404+
}
405+
}

0 commit comments

Comments
 (0)