2021-11-22 16:28:30 +00:00
use crate ::xx ::* ;
use alloc ::string ::ToString ;
2022-05-18 18:09:21 +00:00
use std ::path ::Path ;
2021-11-22 16:28:30 +00:00
2021-12-14 14:48:33 +00:00
#[ macro_export ]
macro_rules ! assert_err {
( $ex :expr ) = > {
if let Ok ( v ) = $ex {
panic! ( " assertion failed, expected Err(..), got {:?} " , v ) ;
}
} ;
}
2021-11-27 17:44:21 +00:00
pub fn split_port ( name : & str ) -> Result < ( String , Option < u16 > ) , String > {
2021-11-22 16:28:30 +00:00
if let Some ( split ) = name . rfind ( ':' ) {
let hoststr = & name [ 0 .. split ] ;
let portstr = & name [ split + 1 .. ] ;
2021-11-27 17:44:21 +00:00
let port : u16 = portstr
. parse ::< u16 > ( )
. map_err ( | e | format! ( " Invalid port: {} " , e ) ) ? ;
2021-11-22 16:28:30 +00:00
2021-11-27 17:44:21 +00:00
Ok ( ( hoststr . to_string ( ) , Some ( port ) ) )
2021-11-22 16:28:30 +00:00
} else {
2021-11-27 17:44:21 +00:00
Ok ( ( name . to_string ( ) , None ) )
2021-11-22 16:28:30 +00:00
}
}
pub fn prepend_slash ( s : String ) -> String {
2021-11-27 17:44:21 +00:00
if s . starts_with ( '/' ) {
2021-11-22 16:28:30 +00:00
return s ;
}
let mut out = " / " . to_owned ( ) ;
out . push_str ( s . as_str ( ) ) ;
out
}
pub fn timestamp_to_secs ( ts : u64 ) -> f64 {
ts as f64 / 1000000.0 f64
}
pub fn secs_to_timestamp ( secs : f64 ) -> u64 {
( secs * 1000000.0 f64 ) as u64
}
2022-01-27 14:53:01 +00:00
pub fn ms_to_us ( ms : u32 ) -> u64 {
( ms as u64 ) * 1000 u64
}
2021-11-22 16:28:30 +00:00
// Calculate retry attempt with logarhythmic falloff
pub fn retry_falloff_log (
last_us : u64 ,
cur_us : u64 ,
interval_start_us : u64 ,
interval_max_us : u64 ,
interval_multiplier_us : f64 ,
) -> bool {
//
if cur_us < interval_start_us {
// Don't require a retry within the first 'interval_start_us' microseconds of the reliable time period
false
} else if cur_us > = last_us + interval_max_us {
// Retry at least every 'interval_max_us' microseconds
true
} else {
// Exponential falloff between 'interval_start_us' and 'interval_max_us' microseconds
2022-05-26 00:56:13 +00:00
last_us < = secs_to_timestamp ( timestamp_to_secs ( cur_us ) / interval_multiplier_us )
2021-11-22 16:28:30 +00:00
}
}
pub fn try_at_most_n_things < T , I , C , R > ( max : usize , things : I , closure : C ) -> Option < R >
where
I : IntoIterator < Item = T > ,
C : Fn ( T ) -> Option < R > ,
{
let mut fails = 0 usize ;
for thing in things . into_iter ( ) {
if let Some ( r ) = closure ( thing ) {
return Some ( r ) ;
}
fails + = 1 ;
if fails > = max {
break ;
}
}
None
}
pub async fn async_try_at_most_n_things < T , I , C , R , F > (
max : usize ,
things : I ,
closure : C ,
) -> Option < R >
where
I : IntoIterator < Item = T > ,
C : Fn ( T ) -> F ,
F : Future < Output = Option < R > > ,
{
let mut fails = 0 usize ;
for thing in things . into_iter ( ) {
if let Some ( r ) = closure ( thing ) . await {
return Some ( r ) ;
}
fails + = 1 ;
if fails > = max {
break ;
}
}
None
}
2021-11-26 14:54:38 +00:00
pub trait CmpAssign {
fn min_assign ( & mut self , other : Self ) ;
fn max_assign ( & mut self , other : Self ) ;
}
impl < T > CmpAssign for T
where
T : core ::cmp ::Ord ,
{
fn min_assign ( & mut self , other : Self ) {
if & other < self {
* self = other ;
}
}
fn max_assign ( & mut self , other : Self ) {
if & other > self {
* self = other ;
}
}
}
2022-03-10 14:51:53 +00:00
pub fn listen_address_to_socket_addrs ( listen_address : & str ) -> Result < Vec < SocketAddr > , String > {
// If no address is specified, but the port is, use ipv4 and ipv6 unspecified
// If the address is specified, only use the specified port and fail otherwise
let ip_addrs = vec! [
IpAddr ::V4 ( Ipv4Addr ::UNSPECIFIED ) ,
IpAddr ::V6 ( Ipv6Addr ::UNSPECIFIED ) ,
] ;
Ok ( if let Some ( portstr ) = listen_address . strip_prefix ( ':' ) {
let port = portstr . parse ::< u16 > ( ) . map_err ( | _ | {
format! (
" Invalid port format in udp listen address: {} " ,
listen_address
)
} ) ? ;
ip_addrs . iter ( ) . map ( | a | SocketAddr ::new ( * a , port ) ) . collect ( )
} else if let Ok ( port ) = listen_address . parse ::< u16 > ( ) {
ip_addrs . iter ( ) . map ( | a | SocketAddr ::new ( * a , port ) ) . collect ( )
} else {
cfg_if! {
if #[ cfg(target_arch = " wasm32 " ) ] {
use core ::str ::FromStr ;
vec! [ SocketAddr ::from_str ( listen_address ) . map_err ( | _ | format! ( " Unable to parse address: {} " , listen_address ) ) ? ]
} else {
listen_address
. to_socket_addrs ( )
. map_err ( | _ | format! ( " Unable to resolve address: {} " , listen_address ) ) ?
. collect ( )
}
}
} )
}
2022-04-24 02:08:02 +00:00
pub trait Dedup < T : PartialEq + Clone > {
fn remove_duplicates ( & mut self ) ;
}
impl < T : PartialEq + Clone > Dedup < T > for Vec < T > {
fn remove_duplicates ( & mut self ) {
let mut already_seen = Vec ::new ( ) ;
self . retain ( | item | match already_seen . contains ( item ) {
true = > false ,
_ = > {
already_seen . push ( item . clone ( ) ) ;
true
}
} )
}
}
2022-05-18 18:09:21 +00:00
cfg_if ::cfg_if! {
if #[ cfg(unix) ] {
use std ::os ::unix ::fs ::MetadataExt ;
use std ::os ::unix ::prelude ::PermissionsExt ;
2022-05-28 14:07:57 +00:00
use nix ::unistd ::{ Uid , Gid } ;
2022-05-18 18:09:21 +00:00
pub fn ensure_file_private_owner < P :AsRef < Path > > ( path : P ) -> Result < ( ) , String >
{
let path = path . as_ref ( ) ;
if ! path . exists ( ) {
return Ok ( ( ) ) ;
}
let uid = Uid ::effective ( ) ;
let gid = Gid ::effective ( ) ;
let meta = std ::fs ::metadata ( path ) . map_err ( | e | format! ( " unable to get metadata for path ' {:?} ': {} " , path , e ) ) ? ;
if meta . mode ( ) ! = 0o600 {
std ::fs ::set_permissions ( path , std ::fs ::Permissions ::from_mode ( 0o600 ) ) . map_err ( | e | format! ( " unable to set correct permissions on path ' {:?} ': {} " , path , e ) ) ? ;
}
if meta . uid ( ) ! = uid . as_raw ( ) | | meta . gid ( ) ! = gid . as_raw ( ) {
2022-05-28 14:07:57 +00:00
return Err ( format! ( " path has incorrect owner/group: {:?} " , path ) ) ;
2022-05-18 18:09:21 +00:00
}
Ok ( ( ) )
}
} else if #[ cfg(windows) ] {
use std ::os ::windows ::fs ::MetadataExt ;
use windows_permissions ::* ;
2022-05-26 00:56:13 +00:00
2022-05-18 18:09:21 +00:00
pub fn ensure_file_private_owner < P :AsRef < Path > > ( path : P ) -> Result < ( ) , String >
{
let path = path . as_ref ( ) ;
if ! path . exists ( ) {
return Ok ( ( ) ) ;
}
// let uid = Uid::effective();
// let gid = Gid::effective();
let meta = std ::fs ::metadata ( path ) . map_err ( | e | format! ( " unable to get metadata for path ' {:?} ': {} " , path , e ) ) ? ;
if meta . mode ( ) ! = 0o600 {
std ::fs ::set_permissions ( path , std ::fs ::Permissions ::from_mode ( 0o600 ) ) . map_err ( | e | format! ( " unable to set correct permissions on path ' {:?} ': {} " , path , e ) ) ? ;
}
2022-05-28 14:07:57 +00:00
//if meta.uid() != uid.as_raw() || meta.gid() != gid.as_raw() {
2022-05-18 18:09:21 +00:00
// chown(path, Some(uid), Some(gid)).map_err(|e| format!("unable to set correct owner on path '{:?}': {}", path, e))?;
2022-05-28 14:07:57 +00:00
//}
2022-05-18 18:09:21 +00:00
Ok ( ( ) )
}
} else {
2022-06-09 00:07:26 +00:00
pub fn ensure_file_private_owner < P :AsRef < Path > > ( _path : P ) -> Result < ( ) , String >
2022-05-18 18:09:21 +00:00
{
Ok ( ( ) )
}
}
}
2022-06-30 02:17:19 +00:00
#[ repr(C, align(8)) ]
struct AlignToEight ( [ u8 ; 8 ] ) ;
pub unsafe fn aligned_8_u8_vec_uninit ( n_bytes : usize ) -> Vec < u8 > {
let n_units = ( n_bytes + mem ::size_of ::< AlignToEight > ( ) - 1 ) / mem ::size_of ::< AlignToEight > ( ) ;
let mut aligned : Vec < AlignToEight > = Vec ::with_capacity ( n_units ) ;
let ptr = aligned . as_mut_ptr ( ) ;
let cap_units = aligned . capacity ( ) ;
mem ::forget ( aligned ) ;
Vec ::from_raw_parts (
ptr as * mut u8 ,
n_bytes ,
cap_units * mem ::size_of ::< AlignToEight > ( ) ,
)
}