2015-10-20 10:15:55 +00:00
|
|
|
use num::{BigUint, Integer, Zero, One};
|
2016-01-02 15:19:39 +00:00
|
|
|
use rand::{Rng, Rand};
|
2015-07-07 21:40:31 +00:00
|
|
|
use std::io;
|
2015-10-20 10:15:55 +00:00
|
|
|
use std::ops::{Mul, Rem, Shr};
|
2015-07-07 21:40:31 +00:00
|
|
|
use std::fs;
|
|
|
|
use std::path::Path;
|
2015-10-20 10:15:55 +00:00
|
|
|
use time;
|
2015-06-23 14:38:29 +00:00
|
|
|
|
|
|
|
mod int128;
|
|
|
|
mod spotify_id;
|
|
|
|
mod arcvec;
|
2015-06-23 17:34:48 +00:00
|
|
|
mod subfile;
|
2015-06-23 14:38:29 +00:00
|
|
|
|
|
|
|
pub use util::int128::u128;
|
|
|
|
pub use util::spotify_id::{SpotifyId, FileId};
|
|
|
|
pub use util::arcvec::ArcVec;
|
2015-06-23 17:34:48 +00:00
|
|
|
pub use util::subfile::Subfile;
|
2015-06-23 14:38:29 +00:00
|
|
|
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! eprintln(
|
|
|
|
($($arg:tt)*) => (
|
|
|
|
{
|
|
|
|
use std::io::Write;
|
|
|
|
writeln!(&mut ::std::io::stderr(), $($arg)* ).unwrap()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! eprint(
|
|
|
|
($($arg:tt)*) => (
|
|
|
|
{
|
|
|
|
use std::io::Write;
|
|
|
|
write!(&mut ::std::io::stderr(), $($arg)* ).unwrap()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
pub fn rand_vec<G: Rng, R: Rand>(rng: &mut G, size: usize) -> Vec<R> {
|
2016-03-16 00:05:05 +00:00
|
|
|
rng.gen_iter().take(size).collect()
|
2015-06-23 14:38:29 +00:00
|
|
|
}
|
|
|
|
|
2016-03-07 18:16:43 +00:00
|
|
|
|
2015-06-23 14:38:29 +00:00
|
|
|
pub mod version {
|
2016-03-07 18:16:43 +00:00
|
|
|
// FIXME: Unfortunately, this doesn't work when using syntex
|
|
|
|
// And for some reason, cfg-gating it doesn't work
|
|
|
|
//include!(concat!(env!("OUT_DIR"), "/version.rs"));
|
|
|
|
pub fn short_sha() -> String {
|
|
|
|
"unknown".to_owned()
|
|
|
|
}
|
2015-06-23 14:38:29 +00:00
|
|
|
|
|
|
|
pub fn version_string() -> String {
|
|
|
|
format!("librespot-{}", short_sha())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn hexdump(data: &[u8]) {
|
|
|
|
for b in data.iter() {
|
|
|
|
eprint!("{:02X} ", b);
|
|
|
|
}
|
|
|
|
eprintln!("");
|
|
|
|
}
|
|
|
|
|
2015-07-02 17:24:25 +00:00
|
|
|
pub trait IgnoreExt {
|
|
|
|
fn ignore(self);
|
|
|
|
}
|
|
|
|
|
2016-01-02 15:19:39 +00:00
|
|
|
impl<T, E> IgnoreExt for Result<T, E> {
|
2015-07-02 17:24:25 +00:00
|
|
|
fn ignore(self) {
|
|
|
|
match self {
|
2016-01-02 15:19:39 +00:00
|
|
|
Ok(_) => (),
|
2015-07-02 17:24:25 +00:00
|
|
|
Err(_) => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-07-02 19:42:49 +00:00
|
|
|
|
|
|
|
pub fn now_ms() -> i64 {
|
|
|
|
let ts = time::now_utc().to_timespec();
|
|
|
|
ts.sec * 1000 + ts.nsec as i64 / 1000000
|
|
|
|
}
|
|
|
|
|
2015-07-07 21:40:31 +00:00
|
|
|
pub fn mkdir_existing(path: &Path) -> io::Result<()> {
|
2016-01-02 15:19:39 +00:00
|
|
|
fs::create_dir(path).or_else(|err| {
|
|
|
|
if err.kind() == io::ErrorKind::AlreadyExists {
|
2015-10-20 10:15:55 +00:00
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(err)
|
2016-01-02 15:19:39 +00:00
|
|
|
}
|
|
|
|
})
|
2015-10-20 10:15:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn powm(base: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint {
|
|
|
|
let mut base = base.clone();
|
|
|
|
let mut exp = exp.clone();
|
2016-01-02 15:19:39 +00:00
|
|
|
let mut result: BigUint = One::one();
|
2015-10-20 10:15:55 +00:00
|
|
|
|
|
|
|
while !exp.is_zero() {
|
|
|
|
if exp.is_odd() {
|
|
|
|
result = result.mul(&base).rem(modulus);
|
|
|
|
}
|
|
|
|
exp = exp.shr(1);
|
|
|
|
base = (&base).mul(&base).rem(modulus);
|
|
|
|
}
|
|
|
|
|
2016-01-02 15:48:44 +00:00
|
|
|
result
|
2015-07-07 21:40:31 +00:00
|
|
|
}
|
|
|
|
|
2015-12-28 15:55:01 +00:00
|
|
|
pub struct StrChunks<'s>(&'s str, usize);
|
|
|
|
|
|
|
|
pub trait StrChunksExt {
|
2016-01-02 15:48:44 +00:00
|
|
|
fn chunks(&self, size: usize) -> StrChunks;
|
2015-12-28 15:55:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl StrChunksExt for str {
|
2016-01-02 15:48:44 +00:00
|
|
|
fn chunks(&self, size: usize) -> StrChunks {
|
2015-12-28 15:55:01 +00:00
|
|
|
StrChunks(self, size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-02 15:19:39 +00:00
|
|
|
impl<'s> Iterator for StrChunks<'s> {
|
2015-12-28 15:55:01 +00:00
|
|
|
type Item = &'s str;
|
|
|
|
fn next(&mut self) -> Option<&'s str> {
|
|
|
|
let &mut StrChunks(data, size) = self;
|
|
|
|
if data.is_empty() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
let ret = Some(&data[..size]);
|
|
|
|
self.0 = &data[size..];
|
|
|
|
ret
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|