use serde::{Deserialize, Serialize};
use std::{
fmt::Debug, fs::{self, DirEntry, ReadDir}, hash::Hash, io::{self, Write}, path::Path, sync::Mutex, time::Instant
};
use crate::prelude::*;
use chrono::{Local, ParseError, Timelike};
pub trait Fromt<T> {
fn fromt(data: &T) -> Self;
}
impl Fromt<dt> for dt {
fn fromt(data: &dt) -> Self {
*data
}
}
impl Fromt<da> for dt {
fn fromt(data: &da) -> Self {
data.and_hms_opt(0, 0, 0).unwrap()
}
}
impl Fromt<Year> for dt {
fn fromt(data: &Year) -> Self {
dt::fromt(&da::fromt(data))
}
}
impl Fromt<&str> for dt {
fn fromt(data: &&str) -> Self {
dt::parse_from_str(data, "%Y-%m-%d %H:%M:%S%.f").unwrap()
}
}
pub trait ToDt {
fn to_dt(&self) -> dt;
}
impl<T> ToDt for T where dt: Fromt<T> {
fn to_dt(&self) -> dt {
dt::fromt(self)
}
}
impl Fromt<dt> for da {
fn fromt(data: &dt) -> Self {
data.date()
}
}
impl Fromt<da> for da {
fn fromt(data: &da) -> Self {
*data
}
}
impl Fromt<Year> for da {
fn fromt(data: &Year) -> Self {
da::from_ymd_opt(data.0 as i32, 1, 1).unwrap()
}
}
impl Fromt<usize> for da {
fn fromt(data: &usize) -> Self {
let year = data / 10000;
let month_date = data % 10000;
let month = month_date / 100;
let date = month_date % 100;
da::from_ymd_opt(year as i32, month as u32, date as u32).unwrap()
}
}
impl Fromt<String> for da {
fn fromt(data: &String) -> Self {
da::parse_from_str(data, "%Y-%m-%d").unwrap()
}
}
impl Fromt<&str> for da {
fn fromt(data: &&str) -> Self {
let res = da::parse_from_str(data, "%Y-%m-%d");
res.expect(data)
}
}
pub trait ToDa {
fn to_da(&self) -> da;
}
impl<T> ToDa for T where da: Fromt<T> {
fn to_da(&self) -> da {
da::fromt(self)
}
}
impl Fromt<dt> for tt {
fn fromt(data: &dt) -> Self {
tt::from_hms_opt(data.hour(), data.minute(), data.second()).unwrap()
}
}
impl Fromt<f64> for tt {
fn fromt(data: &f64) -> Self {
let usize_part = *data as u32;
let float_part = ((data % usize_part as f64) * 1000.) as u32;
let hour = usize_part / 10000;
let minitue_second = usize_part % 10000;
let minitue = minitue_second / 100;
let second = minitue_second % 100;
tt::from_hms_milli_opt(hour, minitue, second, float_part).unwrap()
}
}
impl Fromt<usize> for tt {
fn fromt(data: &usize) -> Self {
tt::fromt(&(*data as f64))
}
}
impl Fromt<&str> for tt {
fn fromt(data: &&str) -> Self {
tt::parse_from_str(data, "%H:%M:%S").unwrap()
}
}
pub trait ToTt {
fn to_tt(&self) -> tt;
}
impl<T> ToTt for T where tt: Fromt<T> {
fn to_tt(&self) -> tt {
tt::fromt(self)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Year(pub usize);
impl Fromt<usize> for Year {
fn fromt(data: &usize) -> Self {
Year(*data)
}
}
pub trait ToYear {
fn to_year(&self) -> Year;
}
impl<T> ToYear for T where Year: Fromt<T> {
fn to_year(&self) -> Year {
Year::fromt(self)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ForCompare<T> {
After(T),
Before(T),
Between(std::ops::Range<T>),
List(Vec<Box<ForCompare<T>>>),
}
impl<T: std::fmt::Debug> std::fmt::Display for ForCompare<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<Self as std::fmt::Debug>::fmt(self, f)
}
}
impl<T> ForCompare<T>
where
T: PartialOrd,
{
pub fn compare_time<N>(&self, other: &N) -> bool
where
T: Fromt<N>,
{
self.compare_same(&T::fromt(other))
}
pub fn compare_same(&self, other: &T) -> bool {
match self {
ForCompare::After(x) => other >= x,
ForCompare::Before(x) => other < x,
ForCompare::Between(x) => x.contains(other),
ForCompare::List(x) => {
for i in x.iter() {
if i.compare_same(other) {
return true
}
}
false
}
}
}
pub fn compare<N>(&self, other: N) -> bool
where
T: From<N>,
{
self.compare_same(&T::from(other))
}
}
pub trait TimeSelect: ToDt {
fn before(&self) -> ForCompare<dt> {
ForCompare::Before(self.to_dt())
}
fn after(&self) -> ForCompare<dt> {
ForCompare::After(self.to_dt())
}
fn to<T: ToDt>(&self, other: T) -> ForCompare<dt> {
ForCompare::Between(self.to_dt()..other.to_dt())
}
}
impl<T: ToDt + Clone> TimeSelect for T {}
pub fn last_days(n: i64) -> ForCompare<dt> {
let today = Local::now().date_naive();
let start_date = today - chrono::Duration::days(n);
start_date.to_da().after()
}
pub trait ToDa2 {
fn to_da2(self) -> Result<da, ParseError>;
}
impl ToDa2 for &str {
fn to_da2(self) -> Result<da, ParseError> {
da::parse_from_str(self, "%Y%m%d")
}
}
pub struct ProgressBar<T> {
t: Instant,
total: Vec<T>,
last_i: Mutex<usize>,
last_l: Mutex<usize>,
thre: usize,
count: usize,
size: usize,
}
impl<T> ProgressBar<T> {
pub fn inc(&self) {
*self.last_i.lock().unwrap() += 1;
let b = *self.last_i.lock().unwrap();
let l = *self.last_l.lock().unwrap();
let t = b.checked_sub(l);
match t {
Some(i) => {
if i >= self.thre || (self.size >= self.thre && b == self.size) {
*self.last_l.lock().unwrap() = b;
self.print();
}
}
None => {
println!("b: {b} l: {l}");
}
}
}
pub fn print(&self) {
println!("{:?} / {:?}, {:.0?}", self.last_i.lock().unwrap(), self.size, self.t.elapsed());
}
}
impl<'a, T> Iterator for ProgressBar<&'a T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
let res = if self.count < self.size {
self.inc();
Some(self.total[self.count])
} else {
None
};
self.count += 1;
res
}
}
pub trait ToProgressBar {
type Output<'a> where Self: 'a;
fn to_progressbar(&self) -> ProgressBar<Self::Output<'_>>;
}
impl<T> ToProgressBar for [T] {
type Output<'a> = &'a T where Self: 'a;
fn to_progressbar(&self) -> ProgressBar<Self::Output<'_>> {
ProgressBar {
t: Instant::now(),
size: self.len(),
total: self.iter().collect_vec(),
last_i: Mutex::new(0),
last_l: Mutex::new(0),
thre: 1000,
count: 0,
}
}
}
impl Iterator for ProgressBar<usize> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
let res = if self.count < self.size {
self.inc();
Some(self.total[self.count])
} else {
None
};
self.count += 1;
res
}
}
impl ToProgressBar for usize {
type Output<'a> = usize;
fn to_progressbar(&self) -> ProgressBar<Self::Output<'_>> {
ProgressBar {
t: Instant::now(),
size: *self,
total: (0..*self).collect_vec(),
last_i: Mutex::new(0),
last_l: Mutex::new(0),
thre: 1000,
count: 0,
}
}
}
impl ToProgressBar for (usize, usize) {
type Output<'a> = usize;
fn to_progressbar(&self) -> ProgressBar<Self::Output<'_>> {
ProgressBar {
t: Instant::now(),
size: self.0,
total: (0..self.0).collect_vec(),
last_i: Mutex::new(0),
last_l: Mutex::new(0),
thre: self.1,
count: 0,
}
}
}
impl ToProgressBar for (usize, f32) {
type Output<'a> = usize;
fn to_progressbar(&self) -> ProgressBar<Self::Output<'_>> {
(self.0, (self.0 as f32 * self.1) as usize).to_progressbar()
}
}
pub trait Pip: Sized {
fn pip<F: Fn(Self) -> T, T>(self, f: F) -> T {
f(self)
}
fn pip_ref<F: Fn(&Self) -> T, T>(&self, f: F) -> T {
f(self)
}
fn pip_clone<F, T>(&self, f: F) -> T
where
Self: Clone,
F: Fn(Self) -> T,
{
self.clone().pip(f)
}
}
impl<T> Pip for T {}
pub trait BoolToOption: Sized {
fn bool_to_option<F>(self, f: F) -> Option<Self>
where
F: Fn(&Self) -> bool,
{
if f(&self) { Some(self) } else { None }
}
fn bool_to_option_else<F, N>(self, f: F, other: N) -> Option<N>
where
F: Fn(Self) -> bool,
{
if f(self) { Some(other) } else { None }
}
}
impl<T> BoolToOption for T {}
pub trait StrHandle: AsRef<str> {
fn split_path(&self) -> (&str, &str) {
let p = Path::new(self.as_ref());
(
p.file_name().unwrap().to_str().unwrap(),
p.parent().unwrap().to_str().unwrap()
)
}
}
impl<T: AsRef<str>> StrHandle for T {}
pub struct DirHandle<T> {
pub dir: String,
pub exclude: Vec<String>,
pub f: T
}
impl<T> DirHandle<T>
where
T: Fn(&str, &str) + Clone,
{
pub fn read_dir(&self) -> ReadDir {
let p = Path::new(&self.dir);
fs::read_dir(p).unwrap()
}
pub fn file_move_change(&self, target: &str) {
if !Path::new(target).is_dir() {
fs::create_dir(target).unwrap_or_else(|_| panic!("not such dir: {:?}", target));
}
for entry in self.read_dir() {
let dir = entry.unwrap();
let b = dir.path();
let f_n = b.file_name().unwrap().to_str().unwrap();
let t_a = format!("{}/{}", target, f_n);
if self.exclude.contains(&f_n.to_string()) {
continue
} else if b.is_dir() {
let handle_dir_next = DirHandle {
dir: b.to_str().unwrap().to_string(),
exclude: self.exclude.clone(),
f: self.f.clone()
};
handle_dir_next.file_move_change(&t_a);
} else {
(self.f)(b.to_str().unwrap(), &t_a);
}
}
}
}
pub trait IntoTuple
where
Self: Sized,
{
fn tuple(&self) -> (Self,)
where
Self: Clone,
{
(self.clone(),)
}
fn into_tuple<T>(self, other: T) -> (Self, T) {
(self, other)
}
}
impl<T: Sized> IntoTuple for T {}
pub trait Print {
fn print(&self)
where
Self: std::fmt::Debug,
{
println!("{:?}", self);
}
fn println(&self)
where
Self: std::fmt::Display,
{
println!("{}", self);
}
fn print_type(&self)
where
Self: Sized,
{
type_of(self);
}
}
impl<T> Print for T {}
pub trait DebugString {
fn debug_string(&self) -> String;
}
impl<T: std::fmt::Debug> DebugString for T {
fn debug_string(&self) -> String {
format!("{:?}", self)
}
}
pub fn copy_dir_for_axum() {
DirHandle {
dir: "/root/arcta".into(),
exclude: vec![
"notebook".into(), "target".into(), "axum".into(),
"OPT2".into(), "data".into()],
f: |x: &str, y: &str| { fs::copy(x, y).unwrap(); },
}
.file_move_change("/root/arcta/axum/crates")
}
pub trait FileStr: AsRef<Path> {
fn clear_dir(&self) {
let path = self.as_ref();
if !path.is_dir() { return }
self
.get_file_vec()
.unwrap_or_default()
.iter()
.for_each(|x| {
path.join(x).remove();
})
}
fn remove(&self) {
let path = Path::new(self.as_ref());
if path.is_dir() {
self.clear_dir();
std::fs::remove_dir(self).unwrap();
} else if path.is_file() {
std::fs::remove_file(self).unwrap();
}
}
fn build_an_empty_dir(&self) {
let path = Path::new(self.as_ref());
if path.is_dir() {
self.clear_dir();
} else {
if path.exists() && path.is_file() {
std::fs::remove_file(path).unwrap();
}
std::fs::create_dir(path).unwrap();
}
}
fn create_a_dir(&self) {
let path = PathBuf::from(self.as_ref());
if !path.exists() {
std::fs::create_dir(path).unwrap();
}
}
fn get_file_vec(&self) -> io::Result<Vec<String>> {
self
.as_ref()
.read_dir()?
.map(|x| {
let path_str = x.unwrap().path();
path_str.file_name_str().to_string()
})
.collect_vec()
.pip(Ok)
}
fn get_file_vec_sort(&self) -> io::Result<Vec<String>> {
let mut res = self.get_file_vec()?;
res.sort();
Ok(res)
}
fn get_file_map(&self) -> io::Result<impl Iterator<Item = DirEntry>> {
self
.as_ref()
.read_dir()?
.map(|x| x.unwrap())
.pip(Ok)
}
fn write_by<T: AsRef<Path> + Debug>(&self, data: T) {
let mut path = std::fs::File
::create(Path::new(self.as_ref())).unwrap();
write!(path, "{:?}", data).unwrap();
}
fn write_to<T: AsRef<Path>>(&self, data: T)
where
Self: Debug,
{
data.write_by(self.as_ref());
}
fn handle_file_recur(&self, f: fn(&Path)) {
if self.as_ref().is_dir() {
self
.get_file_vec()
.unwrap()
.iter()
.for_each(|x| {
self.as_ref().join(x).as_path().handle_file_recur(f);
})
} else {
f(self.as_ref());
}
}
fn file_name_str(&self) -> &str {
self.as_ref().file_name().unwrap().to_str().unwrap()
}
fn parent_str(&self) -> &str {
self.as_ref().parent().unwrap().to_str().unwrap()
}
fn split_dir_and_file(&self) -> (&str, &str) {
(
self.parent_str(),
self.file_name_str(),
)
}
fn file_size(&self) -> f64 {
self.as_ref().metadata().unwrap().len() as f64 / 1024. / 1024.
}
fn check_or_make(&self) {
if !self.as_ref().exists() {
self.build_an_empty_dir()
}
}
}
impl<T: AsRef<Path>> FileStr for T {}
pub trait ToStr {
fn to_str(&self) -> &str;
}
impl ToStr for [u8] {
fn to_str(&self) -> &str {
std::str::from_utf8(self).unwrap()
}
}
pub trait IoTest {
fn io_test(&self);
}
impl<T> IoTest for T
where
for<'de> T: Serialize + Deserialize<'de>,
{
fn io_test(&self) {
t!(self.sof("_", "."));
t!(rof::<T>("_", "."));
"_".file_size().print();
"_".remove();
}
}
use std::path::PathBuf;
pub fn rename_date(p: &PathBuf) -> std::io::Result<()> {
p
.get_file_vec()
.unwrap()
.into_iter()
.for_each(|x| {
let x_new = x.replace('-', "");
let path_old = p.join(&x);
if path_old.is_dir() { panic!() }
let path_new = p.join(x_new);
std::fs::rename(path_old, path_new).unwrap();
});
Ok(())
}
use std::time::SystemTime;
use std::time::UNIX_EPOCH;
use chrono::{DateTime, TimeZone};
pub fn system_time_to_date_time(t: SystemTime) -> DateTime<Local> {
let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
Ok(dur) => (dur.as_secs() as i64, dur.subsec_nanos()),
Err(e) => { let dur = e.duration();
let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());
if nsec == 0 {
(-sec, 0)
} else {
(-sec - 1, 1_000_000_000 - nsec)
}
},
};
Local.timestamp_opt(sec, nsec).unwrap()
}
pub struct DateRange {
start: da,
end: da,
}
pub struct DateRangeIter {
end: da,
last: da,
}
impl DateRange {
pub fn new(start: da, end: da) -> Self {
Self { start, end }
}
}
impl IntoIterator for DateRange {
type Item = da;
type IntoIter = DateRangeIter;
fn into_iter(self) -> Self::IntoIter {
DateRangeIter {
end: self.end,
last: self.start.pred_opt().unwrap(),
}
}
}
impl Iterator for DateRangeIter {
type Item = da;
fn next(&mut self) -> Option<Self::Item> {
if self.last >= self.end {
return None;
}
self.last = self.last.succ_opt()?;
Some(self.last)
}
}
pub trait LeakData {
type Output;
fn leak_data(&self) -> Self::Output;
}
impl<T: Clone + Hash + std::cmp::Eq> LeakData for std::collections::HashMap<T, String> {
type Output = std::collections::HashMap<T, &'static str>;
fn leak_data(&self) -> Self::Output {
self
.iter()
.fold(Self::Output::default(), |mut accu, (k, v)| {
let v_str: &'static str = Box::leak(v.clone().into_boxed_str());
accu.insert(k.clone(), v_str);
accu
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WithInfo<T, N> {
pub data: T,
pub info: N,
}
pub trait WithInfoTrait: Sized {
fn with_info<T>(self, info: T) -> WithInfo<Self, T> {
WithInfo {
data: self,
info,
}
}
}
impl<T> WithInfoTrait for T {}
pub trait GenUniqueId {
fn gen_unique_id(&self, n: usize) -> String
where
Self: std::fmt::Debug,
{
use sha2::{Sha256, Digest};
let input = format!("{self:?}");
let mut hasher = Sha256::new();
hasher.update(input);
let result = hasher.finalize();
hex::encode(result).chars().take(n).collect()
}
}
impl<T> GenUniqueId for T {}