parent
05dbc6a354
commit
649e98b9cc
@ -0,0 +1,68 @@
|
||||
use super::*;
|
||||
use std::{
|
||||
hash::Hash,
|
||||
collections::{HashSet, HashMap},
|
||||
mem,
|
||||
};
|
||||
|
||||
pub trait DedupFullExt
|
||||
{
|
||||
fn dedup_full(&mut self);
|
||||
}
|
||||
|
||||
impl<T> DedupFullExt for Vec<T>
|
||||
where T: Hash + Default + Eq
|
||||
{
|
||||
fn dedup_full(&mut self)
|
||||
{
|
||||
let mut set: HashMap<T, usize> = HashMap::new();
|
||||
for (i,x) in (0..).zip(self.iter_mut())
|
||||
{
|
||||
if !set.contains_key(x) {
|
||||
let us = mem::replace(x, Default::default());
|
||||
set.insert(us, i);
|
||||
}
|
||||
}
|
||||
// To preserve order:
|
||||
let mut tmp = Vec::with_capacity(self.len());
|
||||
for item in set.into_iter()
|
||||
{
|
||||
tmp.push(item);
|
||||
}
|
||||
tmp.sort_by(move |a, b| a.1.partial_cmp(&b.1).unwrap());
|
||||
self.truncate(tmp.len());
|
||||
for (d,s) in self.iter_mut().zip(tmp.into_iter())
|
||||
{
|
||||
*d = s.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test
|
||||
{
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn dedup_full()
|
||||
{
|
||||
let mut vec = vec![
|
||||
"hello",
|
||||
"how",
|
||||
"are",
|
||||
"you",
|
||||
"hello",
|
||||
"hello",
|
||||
"today",
|
||||
"today",
|
||||
"you",
|
||||
"how",
|
||||
"hello",
|
||||
];
|
||||
|
||||
vec.dedup_full();
|
||||
|
||||
assert_eq!(vec.len(), 5);
|
||||
assert_eq!(&vec[..], &["hello","how", "are", "you", "today"]);
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
use super::*;
|
||||
use std::{
|
||||
fmt,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
/// Logging mode
|
||||
#[derive(Debug,Clone,PartialEq,Eq,Hash)]
|
||||
pub enum Mode
|
||||
{
|
||||
/// Output nothing
|
||||
None,
|
||||
/// Only print errors
|
||||
Error,
|
||||
/// Only print warnings
|
||||
Warn,
|
||||
/// Verbose message
|
||||
Verbose,
|
||||
/// Debug messages
|
||||
Debug,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq,Eq,Hash)]
|
||||
pub enum Level
|
||||
{
|
||||
Debug,
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
Fatal,
|
||||
}
|
||||
|
||||
const LEVELS_FOR: &[(Mode, &[Level]); 5] = &[
|
||||
(Mode::None, &[]),
|
||||
(Mode::Error, &[Level::Fatal, Level::Error]),
|
||||
(Mode::Warn, &[Level::Fatal, Level::Error, Level::Warning]),
|
||||
(Mode::Verbose, &[Level::Fatal, Level::Error, Level::Warning, Level::Info]),
|
||||
(Mode::Debug, &[Level::Fatal, Level::Error, Level::Warning, Level::Info, Level::Debug]),
|
||||
];
|
||||
|
||||
impl Mode
|
||||
{
|
||||
/// Can we print this level?
|
||||
#[inline]
|
||||
pub fn level(&self, lv: Level) -> Option<Level>
|
||||
{
|
||||
if lv.mode_ok(self) {
|
||||
Some(lv)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Level
|
||||
{
|
||||
/// Can we print for `mode`?
|
||||
pub fn mode_ok(&self, mode: &Mode) -> bool
|
||||
{
|
||||
use std::collections::{HashMap, HashSet};
|
||||
lazy_static! {
|
||||
static ref MAP: HashMap<&'static Mode, HashSet<&'static Level>> = {
|
||||
let mut m = HashMap::new();
|
||||
for (key, values) in LEVELS_FOR.iter() {
|
||||
let mut set = HashSet::new();
|
||||
for value in values.iter() {
|
||||
set.insert(value);
|
||||
}
|
||||
m.insert(key, set);
|
||||
}
|
||||
m
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(values) = MAP.get(mode) {
|
||||
if values.contains(self) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Level
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
match self {
|
||||
Level::Debug => write!(f, "DEBUG"),
|
||||
Level::Info => write!(f, "INFO"),
|
||||
Level::Warning => write!(f, "WARN"),
|
||||
Level::Error => write!(f, "ERROR"),
|
||||
Level::Fatal => write!(f, "FATAL"),
|
||||
_ => write!(f, "(unbound)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! log {
|
||||
($level:tt, $mode:expr => $format:expr, $($rest:expr),*) => {
|
||||
{
|
||||
|
||||
if let Some(level) = $mode.level($crate::log::Level::$level) {
|
||||
println!("{} [{}]: {}", $crate::log::timestamp(), level, format!($format, $($rest)*));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
}
|
||||
};
|
||||
($mode:expr => $format:expr, $($rest:expr),*) => {
|
||||
{
|
||||
log!(Info, $mode => $format, $($rest)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn timestamp() -> String
|
||||
{
|
||||
use chrono::{
|
||||
offset::Utc,
|
||||
DateTime,
|
||||
};
|
||||
let time: DateTime<Utc> = std::time::SystemTime::now().into();
|
||||
time.format("%Y.%m.%d %h:%M:%S").to_string()
|
||||
}
|
||||
|
||||
//log!(Level::Debug, cmode => "Hello {}", "hi");
|
Loading…
Reference in new issue