mirror of https://git.meli.delivery/meli/meli
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
241 lines
6.4 KiB
Rust
241 lines
6.4 KiB
Rust
/*
|
|
* meli - lib.rs
|
|
*
|
|
* Copyright 2017 Manos Pitsidianakis
|
|
*
|
|
* This file is part of meli.
|
|
*
|
|
* meli is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* meli is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
//! Utility modules for general use.
|
|
|
|
pub mod connections;
|
|
pub mod datetime;
|
|
pub mod futures;
|
|
pub mod random;
|
|
#[macro_use]
|
|
pub mod logging;
|
|
pub mod parsec;
|
|
pub mod percent_encoding;
|
|
pub mod shellexpand;
|
|
#[cfg(feature = "sqlite3")]
|
|
pub mod sqlite3;
|
|
pub mod xdg;
|
|
|
|
pub mod html_escape {
|
|
//! HTML Coded Character Set
|
|
|
|
/// Numeric and Special Graphic Entity Set
|
|
///
|
|
/// ```text
|
|
/// GLYPH NAME SYNTAX DESCRIPTION
|
|
/// < lt < Less than sign
|
|
/// > gt > Greater than sign
|
|
/// & amp & Ampersand
|
|
/// " quot " Double quote sign
|
|
/// ```
|
|
///
|
|
/// Source: <https://www.w3.org/MarkUp/html-spec/html-spec_9.html#SEC9.7.1>
|
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
|
pub enum HtmlEntity {
|
|
/// Less than sign
|
|
Lt,
|
|
/// Greater than sign
|
|
Gt,
|
|
/// Ampersand
|
|
Amp,
|
|
/// Double quote sign
|
|
Quot,
|
|
}
|
|
|
|
impl HtmlEntity {
|
|
pub const ALL: [&'static str; 4] = ["<", ">", "&", """];
|
|
pub const GLYPHS: [&'static str; 4] = ["<", ">", "&", "\""];
|
|
|
|
pub const fn glyph(self) -> char {
|
|
match self {
|
|
Self::Lt => '<',
|
|
Self::Gt => '>',
|
|
Self::Amp => '&',
|
|
Self::Quot => '"',
|
|
}
|
|
}
|
|
|
|
pub const fn name(self) -> &'static str {
|
|
match self {
|
|
Self::Lt => "lt",
|
|
Self::Gt => "gt",
|
|
Self::Amp => "amp",
|
|
Self::Quot => "quot",
|
|
}
|
|
}
|
|
|
|
pub const fn syntax(self) -> &'static str {
|
|
match self {
|
|
Self::Lt => "<",
|
|
Self::Gt => ">",
|
|
Self::Amp => "&",
|
|
Self::Quot => """,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
use std::str::FromStr;
|
|
|
|
#[macro_export]
|
|
macro_rules! declare_u64_hash {
|
|
($type_name:ident) => {
|
|
#[derive(
|
|
Hash,
|
|
Eq,
|
|
PartialEq,
|
|
Debug,
|
|
Ord,
|
|
PartialOrd,
|
|
Default,
|
|
Serialize,
|
|
Deserialize,
|
|
Copy,
|
|
Clone,
|
|
)]
|
|
#[repr(transparent)]
|
|
pub struct $type_name(pub u64);
|
|
|
|
impl $type_name {
|
|
#[inline(always)]
|
|
pub fn from_bytes(bytes: &[u8]) -> Self {
|
|
use std::{collections::hash_map::DefaultHasher, hash::Hasher};
|
|
let mut h = DefaultHasher::new();
|
|
h.write(bytes);
|
|
Self(h.finish())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub const fn to_be_bytes(self) -> [u8; 8] {
|
|
self.0.to_be_bytes()
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub const fn is_null(self) -> bool {
|
|
self.0 == 0
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for $type_name {
|
|
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(fmt, "{}", self.0)
|
|
}
|
|
}
|
|
#[cfg(feature = "sqlite3")]
|
|
impl rusqlite::types::ToSql for $type_name {
|
|
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput> {
|
|
Ok(rusqlite::types::ToSqlOutput::from(self.0 as i64))
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "sqlite3")]
|
|
impl rusqlite::types::FromSql for $type_name {
|
|
fn column_result(
|
|
value: rusqlite::types::ValueRef,
|
|
) -> rusqlite::types::FromSqlResult<Self> {
|
|
let b: i64 = rusqlite::types::FromSql::column_result(value)?;
|
|
|
|
Ok($type_name(b as u64))
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/* Sorting states. */
|
|
|
|
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
|
pub enum SortOrder {
|
|
Asc,
|
|
#[default]
|
|
Desc,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
|
pub enum SortField {
|
|
Subject,
|
|
#[default]
|
|
Date,
|
|
}
|
|
|
|
impl FromStr for SortField {
|
|
type Err = ();
|
|
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
|
match s.trim().to_ascii_lowercase().as_str() {
|
|
"subject" | "s" | "sub" | "sbj" | "subj" => Ok(Self::Subject),
|
|
"date" | "d" => Ok(Self::Date),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FromStr for SortOrder {
|
|
type Err = ();
|
|
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
|
match s.trim().to_ascii_lowercase().as_str() {
|
|
"asc" => Ok(Self::Asc),
|
|
"desc" => Ok(Self::Desc),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::ops::Not for SortOrder {
|
|
type Output = Self;
|
|
|
|
fn not(self) -> Self::Output {
|
|
match self {
|
|
Self::Asc => Self::Desc,
|
|
Self::Desc => Self::Asc,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub mod hostname {
|
|
//! Get local hostname.
|
|
use std::io::Read;
|
|
|
|
use crate::{
|
|
error::{Error, ErrorKind, Result},
|
|
src_err_arc_wrap,
|
|
};
|
|
|
|
/// Get local hostname with the `gethostname()` libc function.
|
|
pub fn hostname() -> Result<std::ffi::OsString> {
|
|
let retval = nix::unistd::gethostname().map_err(|err| {
|
|
Error::new("Could not discover local hostname")
|
|
.set_source(Some(src_err_arc_wrap! {err}))
|
|
.set_kind(ErrorKind::OSError)
|
|
});
|
|
if retval.is_err() {
|
|
let mut hostn_buf = String::with_capacity(256);
|
|
if matches!(
|
|
std::fs::File::open("/etc/hostname")
|
|
.ok()
|
|
.and_then(|mut f| f.read_to_string(&mut hostn_buf).ok()),
|
|
Some(n) if n > 0
|
|
) {
|
|
return Ok(hostn_buf.into());
|
|
}
|
|
}
|
|
retval
|
|
}
|
|
}
|