Skip to content

Instantly share code, notes, and snippets.

@jaoleal
Created October 3, 2024 14:43
Show Gist options
  • Select an option

  • Save jaoleal/d3e1ec7d95416a769c27fdc6a6e40677 to your computer and use it in GitHub Desktop.

Select an option

Save jaoleal/d3e1ec7d95416a769c27fdc6a6e40677 to your computer and use it in GitHub Desktop.
/// Module to group all median-time-past related functions.
pub mod median_time_past {
extern crate alloc;
use alloc::vec;
/// New type to hold the Median-Time-Past value.
pub struct Mtp(u32);
impl Mtp {
/// Gets the MTP value.
pub const fn get_mtp(&self) -> u32 {
self.0
}
pub const fn new_from_value(value: u32) -> Self {
Self(value)
}
}
pub struct MtpContext {
/// The array of timestamps.
pub array: [u32; 11],
/// if the inner array is sorted.
///
/// See [MtpContext::sort()] for more info.
pub is_sorted: bool,
}
impl MtpContext {
pub const fn to_mtp(mut self) -> Mtp {
self.sort();
self.get_mtp().unwrap()
}
/// Creates a [`MtpContext`] from a unique timestamp.
pub const fn new_from_unique(timestamp: u32) -> Self {
Self {
array: [timestamp, 0u32, 0u32, 0u32, 0u32, 0u32, 0u32, 0u32, 0u32, 0u32, 0u32],
is_sorted: true,
}
}
/// Creates a [`MtpContext`] from an unordered array of timestamps.
pub const fn new_from_array(array: [u32; 11]) -> Self {
Self {
array,
is_sorted: false,
}
}
/// Creates a [`MtpContext`] from an unordered iterator of timestamps.
///
/// Basically fills the gap between the sized array and a unsized.
/// The input is anything iterable over u32.
///
/// # Errors
/// Fails if the iterator has more than 11 elements.
///
/// # Examples
/// ```
/// use median_time_past::MtpContext;
/// use rand::Rng;
///
/// pub struct RandomTimestamps(u32);
/// impl RandomTimestamps{
/// pub fn new()-> Self{
/// Self(rand::threadrng().gen::<u32>())
/// }
/// }
///
/// type RandomTimestamps = RTS;
///
/// let array = [RTS::new(),RTS::new(),RTS::new()]
///
/// let array_in_11_elements = [array[0],array[1],array[2], 0u32, 0u32, 0u32, 0u32, 0u32, 0u32, 0u32, 0u32];
///
/// assert_eq!(MtpContext::auto_new_from_array(array.clone()).unwrap().get_array(), array_in_11_elements );
///
/// ```
pub fn auto_new_from_array<A: core::iter::IntoIterator<Item = u32>>(array: A) -> Result<Self, MtpError> {
let mut array = array.into_iter().collect::<vec::Vec<u32>>();
if array.len() > 11 {
return Err(MtpError::ArrayOverflow)
}
array.resize(11, 0);
// I dont see a way to get this done without using try_into.unwrap()
//
// The if statement above ensures the array will always have less than 11 elements.
Ok(Self::new_from_array(array.try_into().unwrap()))
}
/// Creates a [`MtpContext`] from an ordered array of timestamps.
pub const fn new_from_sorted_array(array: [u32; 11]) -> Self {
Self {
array,
is_sorted: true,
}
}
/// Count how much of the timestamps the inner array have.
pub const fn count(&self) -> usize {
self.array.iter().filter(|&x| *x != 0).count()
}
/// Adds a timestamp to the inner array.
pub const fn add(&mut self, timestamp: u32) {
if self.count() == 11 {
self.array[0] = timestamp;
self.is_sorted = false;
} else {
self.array[self.count()] = timestamp;
self.is_sorted = false;
}
}
/// Sorts the inner array.
///
/// The sorts needs to invert so we can use the return of [MtpContext::count()] as a index.
pub const fn sort(&mut self) {
self.array.sort_unstable();
self.array.reverse();
self.is_sorted = true;
}
/// Gets the median-time-past value from the [`MtpContext`] instance.
pub const fn get_mtp(&self) -> Result<Mtp, MtpError> {
if self.is_sorted {
if self.array.len() == 11 {
return Ok(Mtp::new_from_value(self.array[6]))
} else {
return Ok(Mtp::new_from_value(self.array[self.count() / 2]))
}
}
Err(MtpError::UnsortedArray)
}
/// Returns the inner array.
pub const fn get_array(&self) -> [u32; 11] {
self.array
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MtpError {
UnsortedArray,
ArrayOverflow
}
}
impl fmt::Display for MtpError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MtpError::UnsortedArray => write!(f, "The array is not sorted"),
MtpError::ArrayOverflow => write!(f, "The array has more than 11 elements"),
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment