1#![allow(unsafe_op_in_unsafe_fn)]
2
3use core::ptr;
4use libc::{CLOCK_MONOTONIC, clock_gettime, timespec};
5use std::arch::asm;
6
7const DIGITS2: &[u8; 200] = b"\
1900\
2001\
2102\
2203\
2304\
2405\
2506\
2607\
2708\
2809\
2910\
3011\
3112\
3213\
3314\
3415\
3516\
3617\
3718\
3819\
3920\
4021\
4122\
4223\
4324\
4425\
4526\
4627\
4728\
4829\
4930\
5031\
5132\
5233\
5334\
5435\
5536\
5637\
5738\
5839\
5940\
6041\
6142\
6243\
6344\
6445\
6546\
6647\
6748\
6849\
6950\
7051\
7152\
7253\
7354\
7455\
7556\
7657\
7758\
7859\
7960\
8061\
8162\
8263\
8364\
8465\
8566\
8667\
8768\
8869\
8970\
9071\
9172\
9273\
9374\
9475\
9576\
9677\
9778\
9879\
9980\
10081\
10182\
10283\
10384\
10485\
10586\
10687\
10788\
10889\
10990\
11091\
11192\
11293\
11394\
11495\
11596\
11697\
11798\
11899";
119
120const WEEKDAYS: [[u8; 3]; 7] = [
121 *b"Sun", *b"Mon", *b"Tue", *b"Wed", *b"Thu", *b"Fri", *b"Sat",
122];
123
124const MONTHS: [[u8; 3]; 12] = [
125 *b"Jan", *b"Feb", *b"Mar", *b"Apr", *b"May", *b"Jun", *b"Jul", *b"Aug", *b"Sep", *b"Oct",
126 *b"Nov", *b"Dec",
127];
128
129#[inline(always)]
132fn _nano_clock_rs(mut z: i64) -> (i32, u8, u8, u8, u8, u8, u8) {
133 const SECS_PER_DAY: i64 = 86_400;
134 let secs_of_day: u32 = (z % SECS_PER_DAY) as u32;
136 z /= SECS_PER_DAY;
138 let wday: u8 = ((z + 4) % 7) as u8;
140 z += 719_468;
142 let era: i64 = (z >= 0).then(|| z).unwrap_or(z - 146_096) / 146_097;
144 let doe: i64 = z - era * 146_097;
146 let yoe: i64 = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
148 let mut y: i64 = yoe + era * 400;
150 let doy: i64 = doe - (365 * yoe + yoe / 4 - yoe / 100);
152 let mp: i64 = (5 * doy + 2) / 153;
154 let d: u8 = (doy - (153 * mp + 2) / 5 + 1) as u8;
156 let m: i64 = (mp + 2) % 12 + 1;
158 y += mp / 10;
160 let (h, mnt, s): (u8, u8, u8) = (
162 (secs_of_day / 3600) as u8,
163 ((secs_of_day / 60) % 60) as u8,
164 (secs_of_day % 60) as u8,
165 );
166 (y as i32, m as u8, d, h, mnt, s, wday)
168}
169
170#[repr(C)]
171struct YMDHMSW {
172 y: i32,
173 m: u8,
174 d: u8,
175 h: u8,
176 n: u8,
177 s: u8,
178 w: u8,
179}
180
181#[inline(always)]
199unsafe fn _nano_clock_asm(z: i64) -> (i32, u8, u8, u8, u8, u8, u8) {
200 let mut out = YMDHMSW {
201 y: 0,
202 m: 0,
203 d: 0,
204 h: 0,
205 n: 0,
206 s: 0,
207 w: 0,
208 };
209 let out_ptr: *mut YMDHMSW = &mut out as *mut _;
210
211 asm!(
212 "movabs rcx, 1749024623285053783", "mov rax, rsi",
216 "imul rcx",
217 "mov r9, rdx",
218 "mov r10, rdx",
219 "shr r10, 63",
220 "sar r9, 13",
221 "lea rax, [r9 + r10]",
222 "add rax, 719468", "movabs rcx, -62162121600", "cmp rsi, rcx",
226 "lea r8, [r9 + r10 + 573372]",
227 "cmovg r8, rax",
228 "lea rcx, [r9 + r10 + 4]", "movabs rdx, 5270498306774157605", "mov rax, rcx",
232 "imul rdx",
233 "mov rax, rdx",
234 "shr rax, 63",
235 "shr edx, 1",
236 "add edx, eax",
237 "lea eax, [rdx*8]", "sub edx, eax",
239 "add ecx, edx",
240 "mov cl, cl",
241 "add r9, r10",
243 "imul rax, r9, 86400",
244 "sub rsi, rax",
245 "movabs rdx, 4137408090565272301", "mov rax, r8",
248 "imul rdx",
249 "mov r8, rdx",
250 "mov rax, rdx",
251 "shr rax, 63",
252 "sar r8, 15",
253 "add r8, rax",
254 "imul rax, r8, -146097", "add r9, rax",
257 "add r9, 719468", "movabs r13, -3234497591006606311", "mov rax, r9",
261 "imul r13",
262 "mov r10, rdx",
263 "shr r10, 63",
264 "sar rdx, 8",
265 "add r10, rdx",
266
267 "movabs rdx, -1896998432287073591", "mov rax, r9",
269 "imul rdx",
270 "add r10, r9",
271 "lea r11, [rdx + r9]",
272 "mov rax, r11",
274 "shr rax, 63",
275 "sar r11, 15",
276 "add r11, rax",
277 "add r11, r10",
278
279 "movabs rdx, 1896998432287073591", "mov rax, r9",
281 "imul rdx",
282 "sub rdx, r9",
283 "mov r10, rdx",
284 "shr r10, 63",
285 "sar rdx, 17",
286 "add r10, rdx",
287 "add r10, r11",
288 "movabs rdx, 3234497591006606311",
290 "mov rax, r10",
291 "imul rdx",
292 "mov rax, rdx",
293 "shr rax, 63",
294 "sar rdx, 6",
295 "add rdx, rax",
296 "imul r11d, r8d, 400",
297 "add r11d, edx",
298 "imul r14, rdx, -365",
300 "mov rax, r10",
301 "imul r13",
302 "mov r8, rdx",
303 "mov rax, rdx",
304 "shr rax, 63",
305 "sar r8, 8",
306 "add r8, rax",
307
308 "movabs rdx, 2070078458244228039", "mov rax, r10",
310 "imul rdx",
311 "mov rax, rdx",
312 "shr rax, 63",
313 "sar rdx, 12",
314 "add rdx, rax",
315
316 "add r8, r9",
317 "add r8, rdx",
318 "add r8, r14",
319 "lea r10, [r8 + 4*r8 + 2]", "movabs rdx, 3858142551364089227",
322 "mov rax, r10",
323 "imul rdx",
324
325 "mov r9, rdx",
326 "lea r13, [r8 + 4*r8]",
327 "mov r14, rdx",
328 "shr r14, 63",
329 "sar r9, 5",
330 "lea rax, [r9 + r14]",
331 "imul rax, rax, 153", "add rax, 2",
333
334 "movabs rdx, -7378697629483820647",
335 "imul rdx", "mov rax, rdx",
337 "shr rax, 63",
338 "shr edx, 1",
339 "add edx, eax",
340 "add r8d, edx",
341 "inc r8b",
342 "add r9, r14",
344 "add r9, 2",
345 "movabs rdx, 3074457345618258603",
347 "mov rax, r9",
348 "imul rdx",
349 "mov rax, rdx",
350 "shr rax, 63",
351 "shr edx, 1",
352 "add edx, eax",
353 "shl edx, 2",
354 "lea eax, [rdx + 2*rdx]",
355 "sub r9d, eax", "movabs rdx, -6100687909344466089",
358 "mov rax, r10",
359 "imul rdx",
360 "lea rax, [rdx + r13]",
361 "add rax, 2",
362 "mov rdx, rax",
363 "shr rdx, 63",
364 "shr rax, 10",
365 "add eax, edx",
366 "add eax, r11d", "mov edx, esi", "mov r10d, 2443359173", "imul r10, rdx",
371 "shr r10, 43", "mov r11d, 2290649225",
374 "imul r11, rdx",
375 "shr r11, 37", "imul rdx, r11, 143165577",
378 "shr rdx, 33",
379 "imul edx, edx, 60", "imul r13d, r11d, 60",
382 "sub r11d, edx",
383 "sub esi, r13d", "inc r9b", "mov dword ptr [rdi], eax", "mov byte ptr [rdi + 4], r9b", "mov byte ptr [rdi + 5], r8b", "mov byte ptr [rdi + 6], r10b", "mov byte ptr [rdi + 7], r11b", "mov byte ptr [rdi + 8], sil", "mov byte ptr [rdi + 9], cl", inlateout("rsi") z => _,
394 in("rdi") out_ptr,
395 out("rax") _, out("rcx") _, out("rdx") _,
396 out("r8") _, out("r9") _, out("r10") _, out("r11") _,
397 out("r12") _, out("r13") _, out("r14") _, out("r15") _,
398 options(nostack, preserves_flags)
399 );
400 (out.y, out.m, out.d, out.h, out.n, out.s, out.w)
401}
402
403#[inline(always)]
404unsafe fn put2(dst: *mut u8, val: u8) {
405 ptr::copy_nonoverlapping(DIGITS2.as_ptr().add(val as usize * 2), dst, 2);
406}
407
408#[inline(always)]
409pub fn nano_clock() -> (i32, u8, u8, u8, u8, u8, u8) {
410 let t: i64 = unsafe { timestamp() };
411 _nano_clock_rs(t)
412}
413
414#[inline(always)]
415pub fn nano_clock_asm() -> (i32, u8, u8, u8, u8, u8, u8) {
416 let t: i64 = unsafe { timestamp() };
417 unsafe { _nano_clock_asm(t) }
418}
419
420#[inline(always)]
421pub unsafe fn nano_http_date(buf: &mut [u8; 35], use_asm: bool) {
422 let (year, mon, mday, hh, mm, ss, wday): (i32, u8, u8, u8, u8, u8, u8) = match use_asm {
426 true => nano_clock_asm(), false => nano_clock(), };
429 unsafe {
430 ptr::copy_nonoverlapping(b"Date: ".as_ptr(), buf.as_mut_ptr(), 6); ptr::copy_nonoverlapping(WEEKDAYS[wday as usize].as_ptr(), buf.as_mut_ptr().add(6), 3);
434 *buf.get_unchecked_mut(9) = b','; *buf.get_unchecked_mut(10) = b' '; put2(buf.as_mut_ptr().add(11), mday);
438 *buf.get_unchecked_mut(13) = b' '; ptr::copy_nonoverlapping(
441 MONTHS[(mon - 1) as usize].as_ptr(),
442 buf.as_mut_ptr().add(14),
443 3,
444 );
445 *buf.get_unchecked_mut(17) = b' '; let y: u32 = year as u32;
448 put2(buf.as_mut_ptr().add(18), (y / 100) as u8); put2(buf.as_mut_ptr().add(20), (y % 100) as u8); *buf.get_unchecked_mut(22) = b' ';
451 put2(buf.as_mut_ptr().add(23), hh);
453 *buf.get_unchecked_mut(25) = b':';
454 put2(buf.as_mut_ptr().add(26), mm);
455 *buf.get_unchecked_mut(28) = b':';
456 put2(buf.as_mut_ptr().add(29), ss);
457 ptr::copy_nonoverlapping(b" GMT".as_ptr(), buf.as_mut_ptr().add(31), 4);
459 }
460}
461
462#[inline(always)]
463pub unsafe fn timestamp() -> i64 {
464 libc::time(ptr::null_mut()) as i64
465}
466
467#[inline(always)]
468pub unsafe fn nano_timestamp() -> i64 {
469 let mut ts: timespec = std::mem::zeroed();
470 clock_gettime(CLOCK_MONOTONIC, &mut ts);
471 ts.tv_sec as i64 * 1_000_000_000 + ts.tv_nsec as i64
472}