Skip to content

Commit

Permalink
docs, and cleanups / smol tweaks / more generally fix lint warnings
Browse files Browse the repository at this point in the history
and, fix some spellings "safetly" -> "safely", apparently
  • Loading branch information
meadowsys committed Aug 13, 2024
1 parent 104fba4 commit 35825fc
Show file tree
Hide file tree
Showing 17 changed files with 311 additions and 63 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ clock-timer = [
debounce = [
"dep:chrono",
"dep:tokio",
"num-traits-unstable"
"num-traits-unstable",
"with-cloned"
]
defer-unstable = []
export-all-submodules = []
Expand Down
2 changes: 1 addition & 1 deletion scripts/src/bin/gen-features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ fn main() {
"debounce"
"Delay calling a function until a specified period of time has passed since the last time it was called"
dependencies: ["chrono", "tokio"]
features: ["num-traits"]
features: ["num-traits", "with-cloned"]

#[unstable]
"defer"
Expand Down
3 changes: 2 additions & 1 deletion src/_internal/encoding_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::{ slice, ptr };
/// these checks are not run (the `bytes_written` field that tracks it is
/// gated behind `cfg(debug_assertions)`, so doesn't even exist!), and it becomes
/// essentially just a wrapper around a vec, its ptr, raw ptr copying operations,
/// and a method that unsafetly sets the len of the vec before unwrapping it.
/// and a method that unsafely sets the len of the vec before unwrapping it.
///
/// Creating one of these structs is not unsafe, but you can't
/// really do much with it in safe only code :p
Expand Down Expand Up @@ -239,6 +239,7 @@ impl UnsafeBufWriteGuard {
// I cannot remember if I rely on this being repr(transparent) anywhere
#[repr(transparent)]
pub struct ChunkedSlice<'h, const N: usize> {
/// The slice to pull bytes from
bytes: &'h [u8]
}

Expand Down
2 changes: 2 additions & 0 deletions src/_internal/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Internal implementation details and stuff

// TODO: expose this?
#[cfg(any(
// feature = "base16",
Expand Down
2 changes: 2 additions & 0 deletions src/augment_panic_hook/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::panic::{ self, PanicInfo };

/// Augment the panic hook, adding a closure with your own code to
/// be run before the currently set panic hook
#[inline]
pub fn augment_panic_hook(hook: impl Fn(&PanicInfo<'_>) + Send + Sync + 'static) {
let old = panic::take_hook();
Expand Down
2 changes: 1 addition & 1 deletion src/chainer/old/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ impl StringChain {
self
}

/// Unsafetly truncates the string, with no checks at all...
/// Unsafely truncates the string, with no checks at all...
///
/// Unlike the [`truncate`](Self::truncate) method or it's [`String`]
/// equivalent, passing a new len that's past the end of a string
Expand Down
87 changes: 85 additions & 2 deletions src/clock_timer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub use chrono;

use chrono::{ DateTime, Local, NaiveDateTime, TimeDelta, Timelike, TimeZone };
use chrono::{ DateTime, Local, TimeDelta, TimeZone };
use std::future::Future;
use tokio::time::sleep;

Expand All @@ -11,17 +11,61 @@ use tokio::time::sleep;
/// If this falls behind time for some reason, the ticks will be yielded with
/// the time information at when it was supposed to yield, until catching up.
pub struct ClockTimer {
/// The time the next tick will trigger
///
/// In a newly created clock timer, this is the starting time
next_tick: DateTime<Local>,

/// How often this clock timer will yield ticks
interval: TimeDelta,

/// How much time has elapsed since the first tick
///
/// More precisely, this tracks how much time is between the first
/// tick, and the next tick if there is one. Otherwise, the value in this
/// field is meaningless.
elapsed: TimeDelta,

/// How much time is remaining
///
/// More precisely, this tracks how much time is remaining after the time in
/// [`next_tick`](ClockTimer::next_tick)
remaining: TimeDelta
}

/// Timing information for one tick
pub struct Tick {
/// The time of this tick (or, if this tick was delayed, what time this tick
/// was scheduled to be yielded at)
this_tick: DateTime<Local>,

/// The duration from the first tick to this tick (scheduled time),
/// ie. the time the clock timer has been running
elapsed: TimeDelta,

/// The duration from this tick to the last tick (scheduled time),
/// ie. the remaining time the clock timer will run before stopping
remaining: TimeDelta,

/// Whether or not this tick has been delayed
///
/// Note: We have not properly tested this (except in the
/// [april fools prank](https://www.fimfiction.net/story/553695/) that this
/// was built for of course heh), and we suspect this value is always `true`
/// no matter if it was _actually_ delayed by the definition of what you'd
/// expect. You might expect this to be `true` if previous task took too long
/// or something, ie. this was called delayed because of the application
/// logic itself, rather than little OS scheduling runtime things, ie. OS
/// thread scheduling, tokio task scheduling, syncronisation stuff, etc etc.
/// We expect this to always be `true`, because tokio will not wake up and
/// poll again a task until the time has passed, and never before, and if
/// there's any tiny bit of delay introduced anywhere detectable by the time
/// APIs, be it from OS thread syncronisation, or tokio syncronisation, or
/// the arithmetic and time putting the task away to sleep by the async
/// runtime, or something, which, based on how these things work, this will
/// likely always happen and make ths `true`.
///
/// ...whew ramble
delayed: bool
}

Expand Down Expand Up @@ -50,10 +94,16 @@ impl ClockTimer {

let delta = tick.this_tick - Local::now();

// TODO: rethink delayed detection?
// because it is highly likely that due to various factors out of our
// control (eg. OS scheduling, tokio runtime scheduling, work stealing,
// syncronisation stuff, etc etc), we won't get polled until technically
// after our scheduled time, leading this to always be true? tests needed,
// and this delay is in the order of milliseconds, or maybe even micros/nanos
if delta <= TimeDelta::zero() {
// highly unlikely, but if delta somehow manages to hit exactly 0,
// we consider it on time. Maybe we should say like, if now is
// within 1ms after the set tick time? dunno
// within 1ms after the set tick time? dunno (see above todo comment)
if delta < TimeDelta::zero() { tick.delayed = true }
return Some(tick)
}
Expand Down Expand Up @@ -142,11 +192,18 @@ pub mod builder {

/// Builder for [`ClockTimer`].
pub struct Builder {
/// Forcing users to use [`new`] because I dunno style or something, that
/// [`new`] call and this struct is just literally gonna get optimised
/// away to nothing
///
/// [`new`]: Builder::new
__private: ()
}

impl Builder {
/// New builder. You can also obtain a builder through [`ClockTimer::builder`]
// there is no default that makes sense here
#[allow(clippy::new_without_default)]
#[inline]
pub fn new() -> Self {
// its gonna optimise away to be noop lol
Expand All @@ -163,7 +220,13 @@ pub mod builder {
}
}

/// Intermediate builder state struct, returned after calling a method on
/// [`Builder`]
///
/// Most likely you won't need to ever interact with this type directly.
/// You're probably looking for [`Builder`].
pub struct BuilderWithStart {
/// The provided start datetime
start: DateTime<Local>
}

Expand All @@ -188,8 +251,17 @@ pub mod builder {
}
}

/// Intermediate builder state struct, returned after calling a method on
/// [`BuilderWithStart`]
///
/// Most likely you won't need to ever interact with this type directly.
/// You're probably looking for [`Builder`].
pub struct BuilderWithEnd {
/// The provided start datetime (from prev stage of builder)
start: DateTime<Local>,

/// The end datetime, either provided or calculated
/// from a runtime duration
end: DateTime<Local>
}

Expand All @@ -202,9 +274,20 @@ pub mod builder {
}
}

/// Intermediate builder state struct, returned after calling a method on
/// [`BuilderWithEnd`]
///
/// Most likely you won't need to ever interact with this type directly.
/// You're probably looking for [`Builder`].
pub struct BuilderWithInterval {
/// The provided start datetime (from prev stage of builder)
start: DateTime<Local>,

/// The end datetime, either provided or calculated from a runtime
/// duration (from prev stage of builder)
end: DateTime<Local>,

/// The provided trigger interval
interval: TimeDelta
}

Expand Down
16 changes: 15 additions & 1 deletion src/debounce/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::num_traits::*;
use crate::with_cloned;
use chrono::{ Local, NaiveDateTime, TimeDelta };
use std::{ mem::swap, sync::Arc };
use tokio::runtime::Handle;
Expand Down Expand Up @@ -80,10 +81,19 @@ pub fn debounce_immediate_with_rt(
_debounce(Box::new(f), wait_in_ms, true, handle)
}

/// Internal "named args" struct to make things less unwieldy
struct DebounceInternalArgs<F> {
/// The provided function to be debounced
f: F,

/// Whether to call the function "immediately" (ie. on the first
/// fn invocation per "cycle")
immediate: bool,

/// The last time the function was called
last_call_time: Arc<Mutex<Option<NaiveDateTime>>>,

/// Time to wait before triggering a call
debounce_time: TimeDelta
}

Expand All @@ -99,8 +109,11 @@ fn _debounce(
let (fn_caller_sender, fn_caller_receiver) = unbounded_channel();
let last_call_time = Arc::new(Mutex::new(None));

with_cloned! { last_call_time in
rt_handle.spawn(recv_task(receiver, fn_caller_sender, last_call_time));
}

let args = DebounceInternalArgs { f, immediate, last_call_time, debounce_time };
rt_handle.spawn(recv_task(receiver, fn_caller_sender, Arc::clone(&args.last_call_time)));
rt_handle.spawn(fn_caller(fn_caller_receiver, args));

move || sender.send(()).expect("async task for a debounced function was stopped")
Expand Down Expand Up @@ -169,6 +182,7 @@ where
}
}

/// Get the current runtime context, or panic
#[inline]
fn current_rt() -> Handle {
Handle::try_current()
Expand Down
6 changes: 5 additions & 1 deletion src/hex/decode.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
//! Internal decoding implementations

use crate::_internal::encoding_utils::UnsafeBufWriteGuard;
use crate::num_traits::*;
use super::DecodeError;

/// Length of the table decoder (256)
const TABLE_DECODER_LEN: usize = 256;

/// Decoding table (with mappings for both upper and lower hex)
// TODO: this table is mostly empty... I wonder what we could do here to shrink it,
// without compromising speed
// without compromising speed (we could do what we did with z85 with None == 0xff)?
static TABLE_DECODER: &[Option<u8>; TABLE_DECODER_LEN] = &[
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
Expand Down
16 changes: 16 additions & 0 deletions src/hex/encode.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
//! Internal encoding implementations
use crate::_internal::encoding_utils::UnsafeBufWriteGuard;

/// Length of encoding table (not actually used in encoding/decoding data)
pub const TABLE_ENCODER_LEN: usize = 16;

/// Encoding table of lowercased characters, length 16, mapping a value from 0-15
/// to a hex byte (lower letters)
///
/// Note: this table is not actually used in the encoding/decoding implementation
pub static TABLE_ENCODER_LOWER: [u8; TABLE_ENCODER_LEN] = *b"0123456789abcdef";

/// Encoding table of uppercased characters, length 16, mapping a value from 0-15
/// to a hex byte (upper letters)
///
/// Note: this table is not actually used in the encoding/decoding implementation
pub static TABLE_ENCODER_UPPER: [u8; TABLE_ENCODER_LEN] = *b"0123456789ABCDEF";

/// Reads `rounds` bytes from `bytes_ptr`, encoding them into 2 hex chars
/// per byte, then writes the output into `dest`
///
Expand Down
15 changes: 6 additions & 9 deletions src/hex/mod.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use crate::_internal::encoding_utils::UnsafeBufWriteGuard;
use std::str;

/// Length of encoding table (not actually used in encoding/decoding data)
pub const TABLE_ENCODER_LEN: usize = 16;
/// Encoding table of lowercased characters (not actually used in encoding/decoding data)
pub const TABLE_ENCODER_LOWER: [u8; TABLE_ENCODER_LEN] = *b"0123456789abcdef";
/// Encoding table of uppercased characters (not actually used in encoding/decoding data)
pub const TABLE_ENCODER_UPPER: [u8; TABLE_ENCODER_LEN] = *b"0123456789ABCDEF";

mod encode;
mod decode;

pub use self::encode::{
TABLE_ENCODER_LEN,
TABLE_ENCODER_LOWER,
TABLE_ENCODER_UPPER
};

/// Encodes a slice of bytes into a String, using lowercase characters
#[inline]
pub fn encode_hex(bytes: &[u8]) -> String {
Expand All @@ -24,8 +23,6 @@ pub fn encode_hex_upper(bytes: &[u8]) -> String {
}

/// Inner function with const generic `UPPER`
// // mut is used by cfg(target_arch) which is not necessarily cfg enabled
// #[allow(unused_mut)]
fn _encode<const UPPER: bool>(bytes: &[u8]) -> String {
debug_assert!(bytes.len() >> (usize::BITS - 1) == 0, "size overflow");

Expand Down
2 changes: 1 addition & 1 deletion src/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub trait Iter {
/// This method will try to do as little work as possible, and won't advance
/// the iter if it doesn't have to. If the iter's [`size_hint`](Iter::size_hint)
/// returns a [`Single`](SizeHintInner::Single) [`Hard`](SizeHintBound::Hard)
/// bound, this method can safetly return that length, since it is in the
/// bound, this method can safely return that length, since it is in the
/// contract of `size_hint` and hard bounds that the iter must return that
/// many items. Otherwise, it will iterate through the entire iter, counting
/// the number of iterations.
Expand Down
Loading

0 comments on commit 35825fc

Please sign in to comment.