thruster_core/
date.rs

1use std::cell::RefCell;
2use std::fmt::{self, Write};
3use std::str;
4
5use time::{self, Duration};
6
7pub struct Now(());
8
9/// Returns a struct, which when formatted, renders an appropriate `Date` header
10/// value.
11pub fn now() -> Now {
12    Now(())
13}
14
15// Gee Alex, doesn't this seem like premature optimization. Well you see there
16// Billy, you're absolutely correct! If your server is *bottlenecked* on
17// rendering the `Date` header, well then boy do I have news for you, you don't
18// need this optimization.
19//
20// In all seriousness, though, a simple "hello world" benchmark which just sends
21// back literally "hello world" with standard headers actually is bottlenecked
22// on rendering a date into a byte buffer. Since it was at the top of a profile,
23// and this was done for some competitive benchmarks, this module was written.
24//
25// Just to be clear, though, I was not intending on doing this because it really
26// does seem kinda absurd, but it was done by someone else [1], so I blame them!
27// :)
28//
29// [1]: https://github.com/rapidoid/rapidoid/blob/f1c55c0555007e986b5d069fe1086e6d09933f7b/rapidoid-commons/src/main/java/org/rapidoid/commons/Dates.java#L48-L66
30
31struct LastRenderedNow {
32    bytes: [u8; 128],
33    amt: usize,
34    next_update: time::Timespec,
35}
36
37thread_local!(static LAST: RefCell<LastRenderedNow> = RefCell::new(LastRenderedNow {
38    bytes: [0; 128],
39    amt: 0,
40    next_update: time::Timespec::new(0, 0),
41}));
42
43impl fmt::Display for Now {
44    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45        LAST.with(|cache| {
46            let mut cache = cache.borrow_mut();
47            let now = time::get_time();
48            if now > cache.next_update {
49                cache.update(now);
50            }
51            f.write_str(cache.buffer())
52        })
53    }
54}
55
56impl LastRenderedNow {
57    fn buffer(&self) -> &str {
58        str::from_utf8(&self.bytes[..self.amt]).unwrap()
59    }
60
61    fn update(&mut self, now: time::Timespec) {
62        self.amt = 0;
63        write!(LocalBuffer(self), "{}", time::at(now).rfc822()).unwrap();
64        self.next_update = now + Duration::seconds(1);
65        self.next_update.nsec = 0;
66    }
67}
68
69struct LocalBuffer<'a>(&'a mut LastRenderedNow);
70
71impl<'a> fmt::Write for LocalBuffer<'a> {
72    fn write_str(&mut self, s: &str) -> fmt::Result {
73        let start = self.0.amt;
74        let end = start + s.len();
75        self.0.bytes[start..end].copy_from_slice(s.as_bytes());
76        self.0.amt += s.len();
77        Ok(())
78    }
79}