<commit_before>use crate::common::Register;

macro_rules! registers {
    ($struct_name:ident, { $($name:ident = ($val:expr, $disp:expr)),+ $(,)? }) => {
        #[allow(missing_docs)]
        impl $struct_name {
            $(
                pub const $name: Register = Register($val);
            )+
        }

        impl $struct_name {
            /// The name of a register, or `None` if the register number is unknown.
            pub fn register_name(register: Register) -> Option<&'static str> {
                match register {
                    $(
                        Self::$name => Some($disp),
                    )+
                    _ => return None,
                }
            }

	    /// Converts a register name into a register number.
	    pub fn name_to_register(value: &str) -> Option<Register> {
		match value {
                    $(
                        $disp => Some(Self::$name),
                    )+
                    _ => return None,
		}
	    }
        }
    };
}

/// ARM architecture specific definitions.
///
/// See [DWARF for the ARM Architecture](http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040b/IHI0040B_aadwarf.pdf).
#[derive(Debug, Clone, Copy)]
pub struct Arm;

// TODO: add more registers.
registers!(Arm, {
    R0 = (0, "R0"),
    R1 = (1, "R1"),
    R2 = (2, "R2"),
    R3 = (3, "R3"),
    R4 = (4, "R4"),
    R5 = (5, "R5"),
    R6 = (6, "R6"),
    R7 = (7, "R7"),
    R8 = (8, "R8"),
    R9 = (9, "R9"),
    R10 = (10, "R10"),
    R11 = (11, "R11"),
    R12 = (12, "R12"),
    R13 = (13, "R13"),
    R14 = (14, "R14"),
    R15 = (15, "R15"),
});

/// Intel i386 architecture specific definitions.
///
/// See Intel386 psABi version 1.1 at the [X86 psABI wiki](https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI).
#[derive(Debug, Clone, Copy)]
pub struct X86;

registers!(X86, {
    EAX = (0, "eax"),
    ECX = (1, "ecx"),
    EDX = (2, "edx"),
    EBX = (3, "ebx"),
    ESP = (4, "esp"),
    EBP = (5, "ebp"),
    ESI = (6, "esi"),
    EDI = (7, "edi"),

    // Return Address register. This is stored in `0(%esp, "")` and is not a physical register.
    RA = (8, "RA"),

    ST0 = (11, "st0"),
    ST1 = (12, "st1"),
    ST2 = (13, "st2"),
    ST3 = (14, "st3"),
    ST4 = (15, "st4"),
    ST5 = (16, "st5"),
    ST6 = (17, "st6"),
    ST7 = (18, "st7"),

    XMM0 = (21, "xmm0"),
    XMM1 = (22, "xmm1"),
    XMM2 = (23, "xmm2"),
    XMM3 = (24, "xmm3"),
    XMM4 = (25, "xmm4"),
    XMM5 = (26, "xmm5"),
    XMM6 = (27, "xmm6"),
    XMM7 = (28, "xmm7"),

    MM0 = (29, "mm0"),
    MM1 = (30, "mm1"),
    MM2 = (31, "mm2"),
    MM3 = (32, "mm3"),
    MM4 = (33, "mm4"),
    MM5 = (34, "mm5"),
    MM6 = (35, "mm6"),
    MM7 = (36, "mm7"),

    MXCSR = (39, "mxcsr"),

    ES = (40, "es"),
    CS = (41, "cs"),
    SS = (42, "ss"),
    DS = (43, "ds"),
    FS = (44, "fs"),
    GS = (45, "gs"),

    TR = (48, "tr"),
    LDTR = (49, "ldtr"),

    FS_BASE = (93, "fs.base"),
    GS_BASE = (94, "gs.base"),
});

/// AMD64 architecture specific definitions.
///
/// See x86-64 psABI version 1.0 at the [X86 psABI wiki](https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI).
#[derive(Debug, Clone, Copy)]
pub struct X86_64;

registers!(X86_64, {
    RAX = (0, "rax"),
    RDX = (1, "rdx"),
    RCX = (2, "rcx"),
    RBX = (3, "rbx"),
    RSI = (4, "rsi"),
    RDI = (5, "rdi"),
    RBP = (6, "rbp"),
    RSP = (7, "rsp"),

    R8 = (8, "r8"),
    R9 = (9, "r9"),
    R10 = (10, "r10"),
    R11 = (11, "r11"),
    R12 = (12, "r12"),
    R13 = (13, "r13"),
    R14 = (14, "r14"),
    R15 = (15, "r15"),

    // Return Address register. This is stored in `0(%rsp, "")` and is not a physical register.
    RA = (16, "RA"),

    XMM0 = (17, "xmm0"),
    XMM1 = (18, "xmm1"),
    XMM2 = (19, "xmm2"),
    XMM3 = (20, "xmm3"),
    XMM4 = (21, "xmm4"),
    XMM5 = (22, "xmm5"),
    XMM6 = (23, "xmm6"),
    XMM7 = (24, "xmm7"),

    XMM8 = (25, "xmm8"),
    XMM9 = (26, "xmm9"),
    XMM10 = (27, "xmm10"),
    XMM11 = (28, "xmm11"),
    XMM12 = (29, "xmm12"),
    XMM13 = (30, "xmm13"),
    XMM14 = (31, "xmm14"),
    XMM15 = (32, "xmm15"),

    ST0 = (33, "st0"),
    ST1 = (34, "st1"),
    ST2 = (35, "st2"),
    ST3 = (36, "st3"),
    ST4 = (37, "st4"),
    ST5 = (38, "st5"),
    ST6 = (39, "st6"),
    ST7 = (40, "st7"),

    MM0 = (41, "mm0"),
    MM1 = (42, "mm1"),
    MM2 = (43, "mm2"),
    MM3 = (44, "mm3"),
    MM4 = (45, "mm4"),
    MM5 = (46, "mm5"),
    MM6 = (47, "mm6"),
    MM7 = (48, "mm7"),

    RFLAGS = (49, "rFLAGS"),
    ES = (50, "es"),
    CS = (51, "cs"),
    SS = (52, "ss"),
    DS = (53, "ds"),
    FS = (54, "fs"),
    GS = (55, "gs"),

    FS_BASE = (58, "fs.base"),
    GS_BASE = (59, "gs.base"),

    TR = (62, "tr"),
    LDTR = (63, "ldtr"),
    MXCSR = (64, "mxcsr"),
    FCW = (65, "fcw"),
    FSW = (66, "fsw"),

    XMM16 = (67, "xmm16"),
    XMM17 = (68, "xmm17"),
    XMM18 = (69, "xmm18"),
    XMM19 = (70, "xmm19"),
    XMM20 = (71, "xmm20"),
    XMM21 = (72, "xmm21"),
    XMM22 = (73, "xmm22"),
    XMM23 = (74, "xmm23"),
    XMM24 = (75, "xmm24"),
    XMM25 = (76, "xmm25"),
    XMM26 = (77, "xmm26"),
    XMM27 = (78, "xmm27"),
    XMM28 = (79, "xmm28"),
    XMM29 = (80, "xmm29"),
    XMM30 = (81, "xmm30"),
    XMM31 = (82, "xmm31"),

    K0 = (118, "k0"),
    K1 = (119, "k1"),
    K2 = (120, "k2"),
    K3 = (121, "k3"),
    K4 = (122, "k4"),
    K5 = (123, "k5"),
    K6 = (124, "k6"),
    K7 = (125, "k7"),
});
<commit_msg>Add missing ARM and AArch64 register numbers (#574)<commit_after>use crate::common::Register;

macro_rules! registers {
    ($struct_name:ident, { $($name:ident = ($val:expr, $disp:expr)),+ $(,)? }
        $(, aliases { $($alias_name:ident = ($alias_val:expr, $alias_disp:expr)),+ $(,)? })?) => {
        #[allow(missing_docs)]
        impl $struct_name {
            $(
                pub const $name: Register = Register($val);
            )+
            $(
                $(pub const $alias_name: Register = Register($alias_val);)+
            )*
        }

        impl $struct_name {
            /// The name of a register, or `None` if the register number is unknown.
            ///
            /// Only returns the primary name for registers that alias with others.
            pub fn register_name(register: Register) -> Option<&'static str> {
                match register {
                    $(
                        Self::$name => Some($disp),
                    )+
                    _ => return None,
                }
            }

	    /// Converts a register name into a register number.
	    pub fn name_to_register(value: &str) -> Option<Register> {
		match value {
                    $(
                        $disp => Some(Self::$name),
                    )+
                    $(
                        $($alias_disp => Some(Self::$alias_name),)+
                    )*
                    _ => return None,
		}
	    }
        }
    };
}

/// ARM architecture specific definitions.
///
/// See [DWARF for the ARM Architecture](https://developer.arm.com/documentation/ihi0040/c/).
#[derive(Debug, Clone, Copy)]
pub struct Arm;

// TODO: add more registers.
registers!(Arm, {
    R0 = (0, "R0"),
    R1 = (1, "R1"),
    R2 = (2, "R2"),
    R3 = (3, "R3"),
    R4 = (4, "R4"),
    R5 = (5, "R5"),
    R6 = (6, "R6"),
    R7 = (7, "R7"),
    R8 = (8, "R8"),
    R9 = (9, "R9"),
    R10 = (10, "R10"),
    R11 = (11, "R11"),
    R12 = (12, "R12"),
    R13 = (13, "R13"),
    R14 = (14, "R14"),
    R15 = (15, "R15"),

    WCGR0 = (104, "wCGR0"),
    WCGR1 = (105, "wCGR1"),
    WCGR2 = (106, "wCGR2"),
    WCGR3 = (107, "wCGR3"),
    WCGR4 = (108, "wCGR4"),
    WCGR5 = (109, "wCGR5"),
    WCGR6 = (110, "wCGR6"),
    WCGR7 = (111, "wCGR7"),

    WR0 = (112, "wR0"),
    WR1 = (113, "wR1"),
    WR2 = (114, "wR2"),
    WR3 = (115, "wR3"),
    WR4 = (116, "wR4"),
    WR5 = (117, "wR5"),
    WR6 = (118, "wR6"),
    WR7 = (119, "wR7"),
    WR8 = (120, "wR8"),
    WR9 = (121, "wR9"),
    WR10 = (122, "wR10"),
    WR11 = (123, "wR11"),
    WR12 = (124, "wR12"),
    WR13 = (125, "wR13"),
    WR14 = (126, "wR14"),
    WR15 = (127, "wR15"),

    WC0 = (192, "wC0"),
    WC1 = (193, "wC1"),
    WC2 = (194, "wC2"),
    WC3 = (195, "wC3"),
    WC4 = (196, "wC4"),
    WC5 = (197, "wC5"),
    WC6 = (198, "wC6"),
    WC7 = (199, "wC7"),

    D0 = (256, "D0"),
    D1 = (257, "D1"),
    D2 = (258, "D2"),
    D3 = (259, "D3"),
    D4 = (260, "D4"),
    D5 = (261, "D5"),
    D6 = (262, "D6"),
    D7 = (263, "D7"),
    D8 = (264, "D8"),
    D9 = (265, "D9"),
    D10 = (266, "D10"),
    D11 = (267, "D11"),
    D12 = (268, "D12"),
    D13 = (269, "D13"),
    D14 = (270, "D14"),
    D15 = (271, "D15"),
    D16 = (272, "D16"),
    D17 = (273, "D17"),
    D18 = (274, "D18"),
    D19 = (275, "D19"),
    D20 = (276, "D20"),
    D21 = (277, "D21"),
    D22 = (278, "D22"),
    D23 = (279, "D23"),
    D24 = (280, "D24"),
    D25 = (281, "D25"),
    D26 = (282, "D26"),
    D27 = (283, "D27"),
    D28 = (284, "D28"),
    D29 = (285, "D29"),
    D30 = (286, "D30"),
    D31 = (287, "D31"),
},
aliases {
    ACC0 = (104, "ACC0"),
    ACC1 = (105, "ACC1"),
    ACC2 = (106, "ACC2"),
    ACC3 = (107, "ACC3"),
    ACC4 = (108, "ACC4"),
    ACC5 = (109, "ACC5"),
    ACC6 = (110, "ACC6"),
    ACC7 = (111, "ACC7"),

    S0 = (256, "S0"),
    S1 = (256, "S1"),
    S2 = (257, "S2"),
    S3 = (257, "S3"),
    S4 = (258, "S4"),
    S5 = (258, "S5"),
    S6 = (259, "S6"),
    S7 = (259, "S7"),
    S8 = (260, "S8"),
    S9 = (260, "S9"),
    S10 = (261, "S10"),
    S11 = (261, "S11"),
    S12 = (262, "S12"),
    S13 = (262, "S13"),
    S14 = (263, "S14"),
    S15 = (263, "S15"),
    S16 = (264, "S16"),
    S17 = (264, "S17"),
    S18 = (265, "S18"),
    S19 = (265, "S19"),
    S20 = (266, "S20"),
    S21 = (266, "S21"),
    S22 = (267, "S22"),
    S23 = (267, "S23"),
    S24 = (268, "S24"),
    S25 = (268, "S25"),
    S26 = (269, "S26"),
    S27 = (269, "S27"),
    S28 = (270, "S28"),
    S29 = (270, "S29"),
    S30 = (271, "S30"),
    S31 = (271, "S31"),
});

/// ARM 64-bit (AArch64) architecture specific definitions.
///
/// See [DWARF for the ARM 64-bit Architecture](https://developer.arm.com/documentation/ihi0057/b/).
#[derive(Debug, Clone, Copy)]
pub struct AArch64;

registers!(AArch64, {
    X0 = (0, "X0"),
    X1 = (1, "X1"),
    X2 = (2, "X2"),
    X3 = (3, "X3"),
    X4 = (4, "X4"),
    X5 = (5, "X5"),
    X6 = (6, "X6"),
    X7 = (7, "X7"),
    X8 = (8, "X8"),
    X9 = (9, "X9"),
    X10 = (10, "X10"),
    X11 = (11, "X11"),
    X12 = (12, "X12"),
    X13 = (13, "X13"),
    X14 = (14, "X14"),
    X15 = (15, "X15"),
    X16 = (16, "X16"),
    X17 = (17, "X17"),
    X18 = (18, "X18"),
    X19 = (19, "X19"),
    X20 = (20, "X20"),
    X21 = (21, "X21"),
    X22 = (22, "X22"),
    X23 = (23, "X23"),
    X24 = (24, "X24"),
    X25 = (25, "X25"),
    X26 = (26, "X26"),
    X27 = (27, "X27"),
    X28 = (28, "X28"),
    X29 = (29, "X29"),
    X30 = (30, "X30"),
    SP = (31, "SP"),

    V0 = (64, "V0"),
    V1 = (65, "V1"),
    V2 = (66, "V2"),
    V3 = (67, "V3"),
    V4 = (68, "V4"),
    V5 = (69, "V5"),
    V6 = (70, "V6"),
    V7 = (71, "V7"),
    V8 = (72, "V8"),
    V9 = (73, "V9"),
    V10 = (74, "V10"),
    V11 = (75, "V11"),
    V12 = (76, "V12"),
    V13 = (77, "V13"),
    V14 = (78, "V14"),
    V15 = (79, "V15"),
    V16 = (80, "V16"),
    V17 = (81, "V17"),
    V18 = (82, "V18"),
    V19 = (83, "V19"),
    V20 = (84, "V20"),
    V21 = (85, "V21"),
    V22 = (86, "V22"),
    V23 = (87, "V23"),
    V24 = (88, "V24"),
    V25 = (89, "V25"),
    V26 = (90, "V26"),
    V27 = (91, "V27"),
    V28 = (92, "V28"),
    V29 = (93, "V29"),
    V30 = (94, "V30"),
    V31 = (95, "V31"),
});

/// Intel i386 architecture specific definitions.
///
/// See Intel386 psABi version 1.1 at the [X86 psABI wiki](https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI).
#[derive(Debug, Clone, Copy)]
pub struct X86;

registers!(X86, {
    EAX = (0, "eax"),
    ECX = (1, "ecx"),
    EDX = (2, "edx"),
    EBX = (3, "ebx"),
    ESP = (4, "esp"),
    EBP = (5, "ebp"),
    ESI = (6, "esi"),
    EDI = (7, "edi"),

    // Return Address register. This is stored in `0(%esp, "")` and is not a physical register.
    RA = (8, "RA"),

    ST0 = (11, "st0"),
    ST1 = (12, "st1"),
    ST2 = (13, "st2"),
    ST3 = (14, "st3"),
    ST4 = (15, "st4"),
    ST5 = (16, "st5"),
    ST6 = (17, "st6"),
    ST7 = (18, "st7"),

    XMM0 = (21, "xmm0"),
    XMM1 = (22, "xmm1"),
    XMM2 = (23, "xmm2"),
    XMM3 = (24, "xmm3"),
    XMM4 = (25, "xmm4"),
    XMM5 = (26, "xmm5"),
    XMM6 = (27, "xmm6"),
    XMM7 = (28, "xmm7"),

    MM0 = (29, "mm0"),
    MM1 = (30, "mm1"),
    MM2 = (31, "mm2"),
    MM3 = (32, "mm3"),
    MM4 = (33, "mm4"),
    MM5 = (34, "mm5"),
    MM6 = (35, "mm6"),
    MM7 = (36, "mm7"),

    MXCSR = (39, "mxcsr"),

    ES = (40, "es"),
    CS = (41, "cs"),
    SS = (42, "ss"),
    DS = (43, "ds"),
    FS = (44, "fs"),
    GS = (45, "gs"),

    TR = (48, "tr"),
    LDTR = (49, "ldtr"),

    FS_BASE = (93, "fs.base"),
    GS_BASE = (94, "gs.base"),
});

/// AMD64 architecture specific definitions.
///
/// See x86-64 psABI version 1.0 at the [X86 psABI wiki](https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI).
#[derive(Debug, Clone, Copy)]
pub struct X86_64;

registers!(X86_64, {
    RAX = (0, "rax"),
    RDX = (1, "rdx"),
    RCX = (2, "rcx"),
    RBX = (3, "rbx"),
    RSI = (4, "rsi"),
    RDI = (5, "rdi"),
    RBP = (6, "rbp"),
    RSP = (7, "rsp"),

    R8 = (8, "r8"),
    R9 = (9, "r9"),
    R10 = (10, "r10"),
    R11 = (11, "r11"),
    R12 = (12, "r12"),
    R13 = (13, "r13"),
    R14 = (14, "r14"),
    R15 = (15, "r15"),

    // Return Address register. This is stored in `0(%rsp, "")` and is not a physical register.
    RA = (16, "RA"),

    XMM0 = (17, "xmm0"),
    XMM1 = (18, "xmm1"),
    XMM2 = (19, "xmm2"),
    XMM3 = (20, "xmm3"),
    XMM4 = (21, "xmm4"),
    XMM5 = (22, "xmm5"),
    XMM6 = (23, "xmm6"),
    XMM7 = (24, "xmm7"),

    XMM8 = (25, "xmm8"),
    XMM9 = (26, "xmm9"),
    XMM10 = (27, "xmm10"),
    XMM11 = (28, "xmm11"),
    XMM12 = (29, "xmm12"),
    XMM13 = (30, "xmm13"),
    XMM14 = (31, "xmm14"),
    XMM15 = (32, "xmm15"),

    ST0 = (33, "st0"),
    ST1 = (34, "st1"),
    ST2 = (35, "st2"),
    ST3 = (36, "st3"),
    ST4 = (37, "st4"),
    ST5 = (38, "st5"),
    ST6 = (39, "st6"),
    ST7 = (40, "st7"),

    MM0 = (41, "mm0"),
    MM1 = (42, "mm1"),
    MM2 = (43, "mm2"),
    MM3 = (44, "mm3"),
    MM4 = (45, "mm4"),
    MM5 = (46, "mm5"),
    MM6 = (47, "mm6"),
    MM7 = (48, "mm7"),

    RFLAGS = (49, "rFLAGS"),
    ES = (50, "es"),
    CS = (51, "cs"),
    SS = (52, "ss"),
    DS = (53, "ds"),
    FS = (54, "fs"),
    GS = (55, "gs"),

    FS_BASE = (58, "fs.base"),
    GS_BASE = (59, "gs.base"),

    TR = (62, "tr"),
    LDTR = (63, "ldtr"),
    MXCSR = (64, "mxcsr"),
    FCW = (65, "fcw"),
    FSW = (66, "fsw"),

    XMM16 = (67, "xmm16"),
    XMM17 = (68, "xmm17"),
    XMM18 = (69, "xmm18"),
    XMM19 = (70, "xmm19"),
    XMM20 = (71, "xmm20"),
    XMM21 = (72, "xmm21"),
    XMM22 = (73, "xmm22"),
    XMM23 = (74, "xmm23"),
    XMM24 = (75, "xmm24"),
    XMM25 = (76, "xmm25"),
    XMM26 = (77, "xmm26"),
    XMM27 = (78, "xmm27"),
    XMM28 = (79, "xmm28"),
    XMM29 = (80, "xmm29"),
    XMM30 = (81, "xmm30"),
    XMM31 = (82, "xmm31"),

    K0 = (118, "k0"),
    K1 = (119, "k1"),
    K2 = (120, "k2"),
    K3 = (121, "k3"),
    K4 = (122, "k4"),
    K5 = (123, "k5"),
    K6 = (124, "k6"),
    K7 = (125, "k7"),
});
<|endoftext|>


<commit_before>use clap::{App, Arg};
use json5;
use regex::Regex;

use std;
use std::collections::BTreeMap as Map;
use std::env;
use std::fs::File;
use std::io::Read;
use std::net::{IpAddr, SocketAddr};
use std::path::Path;
use std::{process, str};

use crate::{
    config::{Auth, Cert, Config, ProxyRoute, Route},
    consts::*,
    logger::{logger_init, JoinHandle},
};

/// Get `Config` by `parse` `args`
pub fn parse() -> (Config, JoinHandle) {
    let mut config = Config::default();
    let mut server = Server::default();
    let mut routes: Vec<String> = vec!["./".to_owned()];

    let default_addr = server.ip.to_string();
    let default_port = server.port.to_string();
    let default_cache = config.cache_secs.to_string();
    let app = {
        App::new(NAME)
            .version(VERSION)
            .author(env!("CARGO_PKG_AUTHORS"))
            .about(env!("CARGO_PKG_DESCRIPTION"))
            .about(DESC)
            .arg(
                Arg::with_name("qr")
                    .short("Q")
                    .long("qr-code")
                    .help("show URL's QR code at startup"),
            )
            .arg(
                Arg::with_name("verbose")
                    .short("v")
                    .multiple(true)
                    .help("Increases logging verbosity each use for up to 3 times(warn0_info1_debug2_trace3+)"),
            )
            .arg(
                Arg::with_name("config")
                    .long("config")
                    .short("c")
                    .takes_value(true)
                    .help("Set the path to a custom config file"),
            )
            .arg(
                Arg::with_name("auth")
                    .long("auth")
                    .short("a")
                    .takes_value(true)
                    .help("Set the username:password for authorization")
                    .validator(|s| {
                        s.parse::<Auth>()
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for auth: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("cert")
                    .long("cert")
                    .short("C")
                    .takes_value(true)
                    .help("Set the cert for https,  public_key_file:private_key_file")
                    .validator(|s| {
                        s.parse::<Cert>()
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for cert: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("config-print")
                    .long("config-print")
                    .help("Print the default config file"),
            )
            .arg(
                Arg::with_name("redirect-html")
                    .long("redirect-html")
                    .short("r")
                    .help("Redirect dir to `index.html` or `index.htm` if it exists"),
            )
            .arg(
                Arg::with_name("show-hider")
                    .long("show-hider")
                    .short("s")
                    .help("show entries starts with '.'"),
            )
            .arg(
                Arg::with_name("keepalive")
                    .long("keepalive")
                    .short("k")
                    .help("Close HTTP keep alive"),
            )
            .arg(
                Arg::with_name("follow-links")
                    .long("follow-links")
                    .short("f")
                    .help("Whether follow links(default not)"),
            )
            .arg(
                Arg::with_name("upload")
                    .long("upload")
                    .short("u")
                    .help("Whether enable upload(default not)"),
            )
            .arg(
                Arg::with_name("mkdir")
                    .short("m")
                    .long("mkdir")
                    .help("Whether enable mkdir(default not)"),
            )
            .arg(
                Arg::with_name("magic-limit")
                    .long("magic-limit")
                    .short("M")
                    .takes_value(true)
                    .help("The limit for detect file ContenType(use 0 to close)")
                    .validator(|s| {
                        s.parse::<u64>()
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for magic-limit: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("cache-secs")
                    .long("cache-secs")
                    .takes_value(true)
                    .default_value(&default_cache)
                    .help("Set cache secs(use 0 to close)")
                    .validator(|s| {
                        s.parse::<u32>()
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for cache-secs: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("proxy")
                    .long("proxy")
                    .short("P")
                    // .default_value("")
                    .takes_value(true)
                    .help("Enable http proxy function")
                    .validator(|s| {
                        Regex::new(&s)
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for proxy: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("ip")
                    .long("ip")
                    .short("i")
                    .default_value(&default_addr)
                    .takes_value(true)
                    .help("Set listenning ip")
                    .validator(|s| {
                        s.parse::<IpAddr>()
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for ip: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("port")
                    .long("port")
                    .short("p")
                    .default_value(&default_port)
                    .takes_value(true)
                    .help("Set listenning port")
                    .validator(|s| {
                        s.parse::<u16>()
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for port: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("PATH")
                    .index(1)
                    .multiple(true)
                    .help(r#"Set the paths to share"#),
            )
    };

    // clap's NOTE: The first argument will be parsed as the binary name unless AppSettings::NoBinaryName is used
    let args = env::args().collect::<Vec<_>>();
    // not contains other than -v* or --qr
    let args_is_empty = args.iter().skip(1).all(|arg| arg.starts_with("-v") || arg == "--qr");
    let matches = app.get_matches_from(args);
    let qr = matches.is_present("qr");

    // -P/--config-print
    if matches.is_present("config-print") {
        config_print();
    }

    let join_handle = logger_init(matches.occurrences_of("verbose"));

    //-c/--config选项，如果有就载入该文件。
    if let Some(s) = matches.value_of("config") {
        let config = Config::load_from_file(&s)
            .map_err(|e| {
                error!("{:?}", e);
                process::exit(1);
            })
            .unwrap();
        return (config.show_qrcode(qr), join_handle);
    }

    // 命令行有没有参数？有就解析参数，没有就寻找配置文件，再没有就使用默认配置。
    let conf = if args_is_empty {
        match get_config_path() {
            Some(s) => Config::load_from_file(&s)
                .map_err(|e| {
                    error!("{:?}", e);
                    process::exit(1);
                })
                .unwrap(),
            None => Config::load_from_STR(),
        }
    } else {
        let redirect_html = matches.is_present("redirect-html");
        let follow_links = matches.is_present("follow-links");
        let show_hider = matches.is_present("show-hider");
        let upload = matches.is_present("upload");
        let mkdir = matches.is_present("mkdir");
        let authorized = matches.is_present("auth");

        matches.value_of("ip").map(|p| server.ip = p.parse().unwrap());
        matches.value_of("port").map(|p| server.port = p.parse().unwrap());
        matches
            .value_of("cache-secs")
            .map(|cs| config.cache_secs = cs.parse::<u32>().unwrap());

        config.addr = SocketAddr::new(server.ip, server.port);
        config.auth = matches.value_of("auth").map(|cp| cp.parse::<Auth>().unwrap());
        config.cert = matches.value_of("cert").map(|cp| cp.parse::<Cert>().unwrap());
        config.proxy = matches.value_of("proxy").map(|s| (&ProxyRoute::new(true, s)).into());
        config.keep_alive = !matches.is_present("keepalive");
        matches.values_of_lossy("PATH").map(|args| routes = args);

        config.routes = args_paths_to_route(
            &routes[..],
            redirect_html,
            follow_links,
            show_hider,
            upload,
            mkdir,
            authorized,
        )
        .map_err(|e| {
            error!("{:?}", e);
            process::exit(1);
        })
        .unwrap();
        config
    };

    (conf.show_qrcode(qr), join_handle)
}

#[derive(Debug, Clone)]
pub struct Server {
    pub ip: IpAddr,
    pub port: u16,
}

impl Default for Server {
    fn default() -> Server {
        let addr = SERVER_ADDR.get();
        Self::new(addr.ip(), addr.port())
    }
}
impl Server {
    fn new(ip: IpAddr, port: u16) -> Self {
        Server { ip, port }
    }
    fn get_sa() -> SocketAddr {
        Self::default().into()
    }
}

impl Into<SocketAddr> for Server {
    fn into(self) -> SocketAddr {
        SocketAddr::new(self.ip, self.port)
    }
}

// 关键是结构体的字段名，和 json 的[name]对应
#[serde(rename_all = "camelCase")]
#[derive(Debug, Deserialize, Serialize)]
pub struct Fht2p {
    setting: Setting,
    proxy: Option<ProxyRoute>,
    routes: Map<String, Route>,
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Setting {
    #[serde(default = "Server::get_sa")]
    addr: SocketAddr,
    keep_alive: bool,
    magic_limit: u64,
    cache_secs: u32,
    auth: Option<Auth>,
    cert: Option<Cert>,
}

impl Config {
    fn load_from_file(path: &str) -> Result<Self, String> {
        let mut str = String::new();
        let mut file = File::open(path).map_err(|e| format!("config file('{}') open fails: {}", path, e))?;
        file.read_to_string(&mut str)
            .map_err(|e| format!("config file('{}') read fails: {}", path, e))?;
        Self::load_from_str(path, &str)
    }
    fn load_from_str(file_name: &str, json: &str) -> Result<Config, String> {
        let mut config = Self::default();
        config.routes.clear();

        let json: Fht2p = json5::from_str(json).map_err(|e| format!("config file('{}') parse fails: {}", file_name, e))?;
        config.keep_alive = json.setting.keep_alive;
        config.magic_limit = json.setting.magic_limit;
        config.cache_secs = json.setting.cache_secs;
        config.addr = json.setting.addr;
        config.cert = json.setting.cert.clone();
        config.auth = json.setting.auth.clone();
        config.proxy = json.proxy.map(|ref pc| pc.into());

        for (url, route) in &json.routes {
            if !Path::new(&route.path).exists() {
                warn!("'{}''s routes({:?}: {:?}) is not exists", file_name, url, route.path);
            }
            config.routes.insert(
                url.clone(),
                Route::new(
                    url.as_str(),
                    route.path.as_str(),
                    route.redirect_html,
                    route.follow_links,
                    route.show_hider,
                    route.upload,
                    route.mkdir,
                    route.authorized,
                ),
            );
        }
        if config.routes.is_empty() {
            return Err(format!("'{}''s routes is empty", file_name));
        }
        Ok(config)
    }
    #[allow(non_snake_case)]
    fn load_from_STR() -> Self {
        Config::load_from_str("CONFIG-STR", CONFIG_STR).unwrap()
    }
}

// 打印默认配置文件。
fn config_print() {
    println!("{}", CONFIG_STR);
    std::process::exit(0);
}

// 家目录 ～/.config/fht2p/fht2p.json
fn get_config_path() -> Option<String> {
    // using the home_dir function from https://crates.io/crates/dirs instead.
    #[allow(deprecated)]
    let home = std::env::home_dir()?;
    let confp = home.as_path().join(".config/fht2p").join(CONFIG_STR_PATH);
    if confp.exists() {
        Some(confp.to_string_lossy().into_owned())
    } else {
        None
    }
}

// 参数转换为Route url, path
fn args_paths_to_route(
    map: &[String],
    redirect_html: bool,
    follow_links: bool,
    show_hider: bool,
    upload: bool,
    mkdir: bool,
    authorized: bool,
) -> Result<Map<String, Route>, String> {
    let mut routes = Map::new();
    for (idx, path) in map.iter().enumerate() {
        if !Path::new(&path).exists() {
            warn!("{:?} is not exists", &path);
        }
        if idx == 0 {
            let route = Route::new(
                "/".to_owned(),
                path.to_string(),
                redirect_html,
                follow_links,
                show_hider,
                upload,
                mkdir,
                authorized,
            );
            routes.insert("/".to_owned(), route);
        } else {
            let route_url = route_name(path)?;
            let route = Route::new(
                route_url.clone(),
                path.to_string(),
                redirect_html,
                follow_links,
                show_hider,
                upload,
                mkdir,
                authorized,
            );
            if routes.insert(route_url, route).is_some() {
                return Err(format!("{} already defined", route_name(path).unwrap()));
            }
        }
    }
    fn route_name(msg: &str) -> Result<String, String> {
        let path = Path::new(msg);
        path.file_name()
            .map(|s| "/".to_owned() + s.to_str().unwrap())
            .map(|mut s| {
                if Path::new(msg).is_dir() {
                    s.push('/');
                }
                s
            })
            .ok_or_else(|| format!("Path '{}' dost not have name", msg))
    }
    Ok(routes)
}
<commit_msg>add -S as short option for cache-secs<commit_after>use clap::{App, Arg};
use json5;
use regex::Regex;

use std;
use std::collections::BTreeMap as Map;
use std::env;
use std::fs::File;
use std::io::Read;
use std::net::{IpAddr, SocketAddr};
use std::path::Path;
use std::{process, str};

use crate::{
    config::{Auth, Cert, Config, ProxyRoute, Route},
    consts::*,
    logger::{logger_init, JoinHandle},
};

/// Get `Config` by `parse` `args`
pub fn parse() -> (Config, JoinHandle) {
    let mut config = Config::default();
    let mut server = Server::default();
    let mut routes: Vec<String> = vec!["./".to_owned()];

    let default_addr = server.ip.to_string();
    let default_port = server.port.to_string();
    let default_cache = config.cache_secs.to_string();
    let app = {
        App::new(NAME)
            .version(VERSION)
            .author(env!("CARGO_PKG_AUTHORS"))
            .about(env!("CARGO_PKG_DESCRIPTION"))
            .about(DESC)
            .arg(
                Arg::with_name("qr")
                    .short("Q")
                    .long("qr-code")
                    .help("show URL's QR code at startup"),
            )
            .arg(
                Arg::with_name("verbose")
                    .short("v")
                    .multiple(true)
                    .help("Increases logging verbosity each use for up to 3 times(warn0_info1_debug2_trace3+)"),
            )
            .arg(
                Arg::with_name("config")
                    .long("config")
                    .short("c")
                    .takes_value(true)
                    .help("Set the path to a custom config file"),
            )
            .arg(
                Arg::with_name("auth")
                    .long("auth")
                    .short("a")
                    .takes_value(true)
                    .help("Set the username:password for authorization")
                    .validator(|s| {
                        s.parse::<Auth>()
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for auth: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("cert")
                    .long("cert")
                    .short("C")
                    .takes_value(true)
                    .help("Set the cert for https,  public_key_file:private_key_file")
                    .validator(|s| {
                        s.parse::<Cert>()
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for cert: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("config-print")
                    .long("config-print")
                    .help("Print the default config file"),
            )
            .arg(
                Arg::with_name("redirect-html")
                    .long("redirect-html")
                    .short("r")
                    .help("Redirect dir to `index.html` or `index.htm` if it exists"),
            )
            .arg(
                Arg::with_name("show-hider")
                    .long("show-hider")
                    .short("s")
                    .help("show entries starts with '.'"),
            )
            .arg(
                Arg::with_name("keepalive")
                    .long("keepalive")
                    .short("k")
                    .help("Close HTTP keep alive"),
            )
            .arg(
                Arg::with_name("follow-links")
                    .long("follow-links")
                    .short("f")
                    .help("Whether follow links(default not)"),
            )
            .arg(
                Arg::with_name("upload")
                    .long("upload")
                    .short("u")
                    .help("Whether enable upload(default not)"),
            )
            .arg(
                Arg::with_name("mkdir")
                    .short("m")
                    .long("mkdir")
                    .help("Whether enable mkdir(default not)"),
            )
            .arg(
                Arg::with_name("magic-limit")
                    .long("magic-limit")
                    .short("M")
                    .takes_value(true)
                    .help("The limit for detect file ContenType(use 0 to close)")
                    .validator(|s| {
                        s.parse::<u64>()
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for magic-limit: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("cache-secs")
                    .short("S")
                    .long("cache-secs")
                    .takes_value(true)
                    .default_value(&default_cache)
                    .help("Set cache secs(use 0 to close)")
                    .validator(|s| {
                        s.parse::<u32>()
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for cache-secs: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("proxy")
                    .long("proxy")
                    .short("P")
                    // .default_value("")
                    .takes_value(true)
                    .help("Enable http proxy function")
                    .validator(|s| {
                        Regex::new(&s)
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for proxy: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("ip")
                    .long("ip")
                    .short("i")
                    .default_value(&default_addr)
                    .takes_value(true)
                    .help("Set listenning ip")
                    .validator(|s| {
                        s.parse::<IpAddr>()
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for ip: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("port")
                    .long("port")
                    .short("p")
                    .default_value(&default_port)
                    .takes_value(true)
                    .help("Set listenning port")
                    .validator(|s| {
                        s.parse::<u16>()
                            .map(|_| ())
                            .map_err(|e| format!("invalid value for port: {}", e))
                    }),
            )
            .arg(
                Arg::with_name("PATH")
                    .index(1)
                    .multiple(true)
                    .help(r#"Set the paths to share"#),
            )
    };

    // clap's NOTE: The first argument will be parsed as the binary name unless AppSettings::NoBinaryName is used
    let args = env::args().collect::<Vec<_>>();
    // not contains other than -v* or --qr
    let args_is_empty = args.iter().skip(1).all(|arg| arg.starts_with("-v") || arg == "--qr");
    let matches = app.get_matches_from(args);
    let qr = matches.is_present("qr");

    // -P/--config-print
    if matches.is_present("config-print") {
        config_print();
    }

    let join_handle = logger_init(matches.occurrences_of("verbose"));

    //-c/--config选项，如果有就载入该文件。
    if let Some(s) = matches.value_of("config") {
        let config = Config::load_from_file(&s)
            .map_err(|e| {
                error!("{:?}", e);
                process::exit(1);
            })
            .unwrap();
        return (config.show_qrcode(qr), join_handle);
    }

    // 命令行有没有参数？有就解析参数，没有就寻找配置文件，再没有就使用默认配置。
    let conf = if args_is_empty {
        match get_config_path() {
            Some(s) => Config::load_from_file(&s)
                .map_err(|e| {
                    error!("{:?}", e);
                    process::exit(1);
                })
                .unwrap(),
            None => Config::load_from_STR(),
        }
    } else {
        let redirect_html = matches.is_present("redirect-html");
        let follow_links = matches.is_present("follow-links");
        let show_hider = matches.is_present("show-hider");
        let upload = matches.is_present("upload");
        let mkdir = matches.is_present("mkdir");
        let authorized = matches.is_present("auth");

        matches.value_of("ip").map(|p| server.ip = p.parse().unwrap());
        matches.value_of("port").map(|p| server.port = p.parse().unwrap());
        matches
            .value_of("cache-secs")
            .map(|cs| config.cache_secs = cs.parse::<u32>().unwrap());

        config.addr = SocketAddr::new(server.ip, server.port);
        config.auth = matches.value_of("auth").map(|cp| cp.parse::<Auth>().unwrap());
        config.cert = matches.value_of("cert").map(|cp| cp.parse::<Cert>().unwrap());
        config.proxy = matches.value_of("proxy").map(|s| (&ProxyRoute::new(true, s)).into());
        config.keep_alive = !matches.is_present("keepalive");
        matches.values_of_lossy("PATH").map(|args| routes = args);

        config.routes = args_paths_to_route(
            &routes[..],
            redirect_html,
            follow_links,
            show_hider,
            upload,
            mkdir,
            authorized,
        )
        .map_err(|e| {
            error!("{:?}", e);
            process::exit(1);
        })
        .unwrap();
        config
    };

    (conf.show_qrcode(qr), join_handle)
}

#[derive(Debug, Clone)]
pub struct Server {
    pub ip: IpAddr,
    pub port: u16,
}

impl Default for Server {
    fn default() -> Server {
        let addr = SERVER_ADDR.get();
        Self::new(addr.ip(), addr.port())
    }
}
impl Server {
    fn new(ip: IpAddr, port: u16) -> Self {
        Server { ip, port }
    }
    fn get_sa() -> SocketAddr {
        Self::default().into()
    }
}

impl Into<SocketAddr> for Server {
    fn into(self) -> SocketAddr {
        SocketAddr::new(self.ip, self.port)
    }
}

// 关键是结构体的字段名，和 json 的[name]对应
#[serde(rename_all = "camelCase")]
#[derive(Debug, Deserialize, Serialize)]
pub struct Fht2p {
    setting: Setting,
    proxy: Option<ProxyRoute>,
    routes: Map<String, Route>,
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Setting {
    #[serde(default = "Server::get_sa")]
    addr: SocketAddr,
    keep_alive: bool,
    magic_limit: u64,
    cache_secs: u32,
    auth: Option<Auth>,
    cert: Option<Cert>,
}

impl Config {
    fn load_from_file(path: &str) -> Result<Self, String> {
        let mut str = String::new();
        let mut file = File::open(path).map_err(|e| format!("config file('{}') open fails: {}", path, e))?;
        file.read_to_string(&mut str)
            .map_err(|e| format!("config file('{}') read fails: {}", path, e))?;
        Self::load_from_str(path, &str)
    }
    fn load_from_str(file_name: &str, json: &str) -> Result<Config, String> {
        let mut config = Self::default();
        config.routes.clear();

        let json: Fht2p = json5::from_str(json).map_err(|e| format!("config file('{}') parse fails: {}", file_name, e))?;
        config.keep_alive = json.setting.keep_alive;
        config.magic_limit = json.setting.magic_limit;
        config.cache_secs = json.setting.cache_secs;
        config.addr = json.setting.addr;
        config.cert = json.setting.cert.clone();
        config.auth = json.setting.auth.clone();
        config.proxy = json.proxy.map(|ref pc| pc.into());

        for (url, route) in &json.routes {
            if !Path::new(&route.path).exists() {
                warn!("'{}''s routes({:?}: {:?}) is not exists", file_name, url, route.path);
            }
            config.routes.insert(
                url.clone(),
                Route::new(
                    url.as_str(),
                    route.path.as_str(),
                    route.redirect_html,
                    route.follow_links,
                    route.show_hider,
                    route.upload,
                    route.mkdir,
                    route.authorized,
                ),
            );
        }
        if config.routes.is_empty() {
            return Err(format!("'{}''s routes is empty", file_name));
        }
        Ok(config)
    }
    #[allow(non_snake_case)]
    fn load_from_STR() -> Self {
        Config::load_from_str("CONFIG-STR", CONFIG_STR).unwrap()
    }
}

// 打印默认配置文件。
fn config_print() {
    println!("{}", CONFIG_STR);
    std::process::exit(0);
}

// 家目录 ～/.config/fht2p/fht2p.json
fn get_config_path() -> Option<String> {
    // using the home_dir function from https://crates.io/crates/dirs instead.
    #[allow(deprecated)]
    let home = std::env::home_dir()?;
    let confp = home.as_path().join(".config/fht2p").join(CONFIG_STR_PATH);
    if confp.exists() {
        Some(confp.to_string_lossy().into_owned())
    } else {
        None
    }
}

// 参数转换为Route url, path
fn args_paths_to_route(
    map: &[String],
    redirect_html: bool,
    follow_links: bool,
    show_hider: bool,
    upload: bool,
    mkdir: bool,
    authorized: bool,
) -> Result<Map<String, Route>, String> {
    let mut routes = Map::new();
    for (idx, path) in map.iter().enumerate() {
        if !Path::new(&path).exists() {
            warn!("{:?} is not exists", &path);
        }
        if idx == 0 {
            let route = Route::new(
                "/".to_owned(),
                path.to_string(),
                redirect_html,
                follow_links,
                show_hider,
                upload,
                mkdir,
                authorized,
            );
            routes.insert("/".to_owned(), route);
        } else {
            let route_url = route_name(path)?;
            let route = Route::new(
                route_url.clone(),
                path.to_string(),
                redirect_html,
                follow_links,
                show_hider,
                upload,
                mkdir,
                authorized,
            );
            if routes.insert(route_url, route).is_some() {
                return Err(format!("{} already defined", route_name(path).unwrap()));
            }
        }
    }
    fn route_name(msg: &str) -> Result<String, String> {
        let path = Path::new(msg);
        path.file_name()
            .map(|s| "/".to_owned() + s.to_str().unwrap())
            .map(|mut s| {
                if Path::new(msg).is_dir() {
                    s.push('/');
                }
                s
            })
            .ok_or_else(|| format!("Path '{}' dost not have name", msg))
    }
    Ok(routes)
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use glib_ffi;
use std::ptr;
use std::mem;
use glib::translate::*;

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Atom(ffi::GdkAtom);

pub const NONE: Atom = Atom(0 as *mut _);
pub const SELECTION_PRIMARY: Atom = Atom(1 as *mut _);
pub const SELECTION_SECONDARY: Atom = Atom(2 as *mut _);
pub const SELECTION_CLIPBOARD: Atom = Atom(69 as *mut _);
pub const TARGET_BITMAP: Atom = Atom(5 as *mut _);
pub const TARGET_COLORMAP: Atom = Atom(7 as *mut _);
pub const TARGET_DRAWABLE: Atom = Atom(17 as *mut _);
pub const TARGET_PIXMAP: Atom = Atom(20 as *mut _);
pub const TARGET_STRING: Atom = Atom(31 as *mut _);
pub const SELECTION_TYPE_ATOM: Atom = Atom(4 as *mut _);
pub const SELECTION_TYPE_BITMAP: Atom = Atom(5 as *mut _);
pub const SELECTION_TYPE_COLORMAP: Atom = Atom(7 as *mut _);
pub const SELECTION_TYPE_DRAWABLE: Atom = Atom(17 as *mut _);
pub const SELECTION_TYPE_INTEGER: Atom = Atom(19 as *mut _);
pub const SELECTION_TYPE_PIXMAP: Atom = Atom(20 as *mut _);
pub const SELECTION_TYPE_WINDOW: Atom = Atom(33 as *mut _);
pub const SELECTION_TYPE_STRING: Atom = Atom(31 as *mut _);

impl Atom {
    pub fn intern(atom_name: &str) -> Atom {
        assert_initialized_main_thread!();
        unsafe { Atom(ffi::gdk_atom_intern(atom_name.to_glib_none().0, false.to_glib())) }
    }

    pub fn name(&self) -> String {
        unsafe { from_glib_full(ffi::gdk_atom_name(self.0)) }
    }

    pub unsafe fn value(&self) -> usize {
        self.0 as usize
    }
}

impl GlibPtrDefault for Atom {
    type GlibType = ffi::GdkAtom;
}

impl<'a> ToGlibPtr<'a, ffi::GdkAtom> for Atom {
    type Storage = ();

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, ffi::GdkAtom, Atom> {
        Stash(self.0, ())
    }
}

impl<'a> ToGlibContainerFromSlice<'a, *mut ffi::GdkAtom> for &'a Atom {
    type Storage = (Vec<Stash<'a, ffi::GdkAtom, &'a Atom>>, Option<Vec<ffi::GdkAtom>>);

    fn to_glib_none_from_slice(t: &'a [&'a Atom]) -> (*mut ffi::GdkAtom, Self::Storage) {
        let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();
        let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
        v_ptr.push(0 as *mut _);

        (v_ptr.as_ptr() as *mut ffi::GdkAtom, (v, Some(v_ptr)))
    }

    fn to_glib_container_from_slice(t: &'a [&'a Atom]) -> (*mut ffi::GdkAtom, Self::Storage) {
        let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();

        let v_ptr = unsafe {
            let v_ptr = glib_ffi::g_malloc0(mem::size_of::<ffi::GdkAtom>() * t.len() + 1) as *mut ffi::GdkAtom;

            for (i, s) in v.iter().enumerate() {
                ptr::write(v_ptr.offset(i as isize), s.0);
            }

            v_ptr
        };

        (v_ptr, (v, None))
    }

    fn to_glib_full_from_slice(_: &[&'a Atom]) -> *mut ffi::GdkAtom {
        unimplemented!()
    }
}

impl FromGlibPtrNone<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_none(ptr: ffi::GdkAtom) -> Atom { Atom(ptr) }
}

impl FromGlibPtrFull<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_full(_: ffi::GdkAtom) -> Atom { unimplemented!() }
}

impl FromGlibContainerAsVec<ffi::GdkAtom, *mut ffi::GdkAtom> for Atom {
    unsafe fn from_glib_none_num_as_vec(mut ptr: *mut ffi::GdkAtom, num: usize) -> Vec<Self> {
        if num == 0 || ptr.is_null() {
            return Vec::new();
        }

        let mut res = Vec::with_capacity(num);
        for _ in 0..num {
            res.push(from_glib_none(ptr::read(ptr)));
            ptr = ptr.offset(1);
        }
        res
    }

    unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GdkAtom, num: usize) -> Vec<Self> {
        let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
        glib_ffi::g_free(ptr as *mut _);
        res
    }

    unsafe fn from_glib_full_num_as_vec(mut ptr: *mut ffi::GdkAtom, num: usize) -> Vec<Self> {
        if num == 0 || ptr.is_null() {
            return Vec::new();
        }

        let mut res = Vec::with_capacity(num);
        for _ in 0..num {
            res.push(from_glib_full(ptr::read(ptr)));
            ptr = ptr.offset(1);
        }
        glib_ffi::g_free(ptr as *mut _);
        res
    }
}

impl FromGlibPtrArrayContainerAsVec<ffi::GdkAtom, *mut ffi::GdkAtom> for Atom {
    unsafe fn from_glib_none_as_vec(ptr: *mut ffi::GdkAtom) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
    }

    unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GdkAtom) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr))
    }

    unsafe fn from_glib_full_as_vec(ptr: *mut ffi::GdkAtom) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
    }
}

impl<'a> From<&'a str> for Atom {
    fn from(r: &'a str) -> Atom {
        skip_assert_initialized!();
        Atom::intern(r)
    }
}
<commit_msg>Fix transfer full conversion of Atom arrays<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use glib_ffi;
use std::ptr;
use std::mem;
use glib::translate::*;

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Atom(ffi::GdkAtom);

pub const NONE: Atom = Atom(0 as *mut _);
pub const SELECTION_PRIMARY: Atom = Atom(1 as *mut _);
pub const SELECTION_SECONDARY: Atom = Atom(2 as *mut _);
pub const SELECTION_CLIPBOARD: Atom = Atom(69 as *mut _);
pub const TARGET_BITMAP: Atom = Atom(5 as *mut _);
pub const TARGET_COLORMAP: Atom = Atom(7 as *mut _);
pub const TARGET_DRAWABLE: Atom = Atom(17 as *mut _);
pub const TARGET_PIXMAP: Atom = Atom(20 as *mut _);
pub const TARGET_STRING: Atom = Atom(31 as *mut _);
pub const SELECTION_TYPE_ATOM: Atom = Atom(4 as *mut _);
pub const SELECTION_TYPE_BITMAP: Atom = Atom(5 as *mut _);
pub const SELECTION_TYPE_COLORMAP: Atom = Atom(7 as *mut _);
pub const SELECTION_TYPE_DRAWABLE: Atom = Atom(17 as *mut _);
pub const SELECTION_TYPE_INTEGER: Atom = Atom(19 as *mut _);
pub const SELECTION_TYPE_PIXMAP: Atom = Atom(20 as *mut _);
pub const SELECTION_TYPE_WINDOW: Atom = Atom(33 as *mut _);
pub const SELECTION_TYPE_STRING: Atom = Atom(31 as *mut _);

impl Atom {
    pub fn intern(atom_name: &str) -> Atom {
        assert_initialized_main_thread!();
        unsafe { Atom(ffi::gdk_atom_intern(atom_name.to_glib_none().0, false.to_glib())) }
    }

    pub fn name(&self) -> String {
        unsafe { from_glib_full(ffi::gdk_atom_name(self.0)) }
    }

    pub unsafe fn value(&self) -> usize {
        self.0 as usize
    }
}

impl GlibPtrDefault for Atom {
    type GlibType = ffi::GdkAtom;
}

impl<'a> ToGlibPtr<'a, ffi::GdkAtom> for Atom {
    type Storage = ();

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, ffi::GdkAtom, Atom> {
        Stash(self.0, ())
    }
}

impl<'a> ToGlibContainerFromSlice<'a, *mut ffi::GdkAtom> for &'a Atom {
    type Storage = (Vec<Stash<'a, ffi::GdkAtom, &'a Atom>>, Option<Vec<ffi::GdkAtom>>);

    fn to_glib_none_from_slice(t: &'a [&'a Atom]) -> (*mut ffi::GdkAtom, Self::Storage) {
        let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();
        let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
        v_ptr.push(0 as *mut _);

        (v_ptr.as_ptr() as *mut ffi::GdkAtom, (v, Some(v_ptr)))
    }

    fn to_glib_container_from_slice(t: &'a [&'a Atom]) -> (*mut ffi::GdkAtom, Self::Storage) {
        let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();

        let v_ptr = unsafe {
            let v_ptr = glib_ffi::g_malloc0(mem::size_of::<ffi::GdkAtom>() * t.len() + 1) as *mut ffi::GdkAtom;

            for (i, s) in v.iter().enumerate() {
                ptr::write(v_ptr.offset(i as isize), s.0);
            }

            v_ptr
        };

        (v_ptr, (v, None))
    }

    fn to_glib_full_from_slice(_: &[&'a Atom]) -> *mut ffi::GdkAtom {
        unimplemented!()
    }
}

impl FromGlibPtrNone<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_none(ptr: ffi::GdkAtom) -> Atom { Atom(ptr) }
}

impl FromGlibPtrFull<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_full(_: ffi::GdkAtom) -> Atom { unimplemented!() }
}

impl FromGlibContainerAsVec<ffi::GdkAtom, *mut ffi::GdkAtom> for Atom {
    unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GdkAtom, num: usize) -> Vec<Self> {
        if num == 0 || ptr.is_null() {
            return Vec::new();
        }

        let mut res = Vec::with_capacity(num);
        for i in 0..num {
            res.push(from_glib_none(ptr::read(ptr.offset(i as isize))));
        }
        res
    }

    unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GdkAtom, num: usize) -> Vec<Self> {
        let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
        glib_ffi::g_free(ptr as *mut _);
        res
    }

    unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GdkAtom, num: usize) -> Vec<Self> {
        if num == 0 || ptr.is_null() {
            return Vec::new();
        }

        let mut res = Vec::with_capacity(num);
        for i in 0..num {
            res.push(from_glib_full(ptr::read(ptr.offset(i as isize))));
        }
        glib_ffi::g_free(ptr as *mut _);
        res
    }
}

impl FromGlibPtrArrayContainerAsVec<ffi::GdkAtom, *mut ffi::GdkAtom> for Atom {
    unsafe fn from_glib_none_as_vec(ptr: *mut ffi::GdkAtom) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
    }

    unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GdkAtom) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr))
    }

    unsafe fn from_glib_full_as_vec(ptr: *mut ffi::GdkAtom) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
    }
}

impl<'a> From<&'a str> for Atom {
    fn from(r: &'a str) -> Atom {
        skip_assert_initialized!();
        Atom::intern(r)
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use evcxr::{self, EvalContext};
use std::io;
use std::sync::mpsc;

fn send_output<T: io::Write + Send + 'static>(channel: mpsc::Receiver<String>, mut output: T) {
    std::thread::spawn(move || {
        while let Ok(line) = channel.recv() {
            if writeln!(output, "{}", line).is_err() {
                break;
            }
        }
    });
}

fn has_nightly_compiler() -> bool {
    use std::process;
    match process::Command::new("cargo")
        .arg("+nightly")
        .arg("help")
        .stdout(process::Stdio::null())
        .stderr(process::Stdio::null())
        .status()
    {
        Ok(exit_status) => exit_status.success(),
        Err(_) => false,
    }
}

fn main() -> Result<(), evcxr::Error> {
    evcxr::runtime_hook();
    if !has_nightly_compiler() {
        println!("print_performance_info: Nightly compiler is required.");
        // Exit with Ok status. We run this from Travis CI and don't want to
        // fail when it gets run on non-nightly configurations.
        return Ok(());
    }
    let (mut ctx, outputs) = EvalContext::new()?;
    send_output(outputs.stderr, io::stderr());
    ctx.set_time_passes(true);
    ctx.eval("println!(\"41\");")?;
    ctx.eval("println!(\"42\");")?;
    Ok(())
}
<commit_msg>Print timings from evcxr's perspective as well<commit_after>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use evcxr::{self, EvalContext};
use std::io;
use std::sync::mpsc;

fn send_output<T: io::Write + Send + 'static>(channel: mpsc::Receiver<String>, mut output: T) {
    std::thread::spawn(move || {
        while let Ok(line) = channel.recv() {
            if writeln!(output, "{}", line).is_err() {
                break;
            }
        }
    });
}

fn has_nightly_compiler() -> bool {
    use std::process;
    match process::Command::new("cargo")
        .arg("+nightly")
        .arg("help")
        .stdout(process::Stdio::null())
        .stderr(process::Stdio::null())
        .status()
    {
        Ok(exit_status) => exit_status.success(),
        Err(_) => false,
    }
}

fn main() -> Result<(), evcxr::Error> {
    use std::time::Instant;
    evcxr::runtime_hook();
    if !has_nightly_compiler() {
        println!("print_performance_info: Nightly compiler is required.");
        // Exit with Ok status. We run this from Travis CI and don't want to
        // fail when it gets run on non-nightly configurations.
        return Ok(());
    }
    let (mut ctx, outputs) = EvalContext::new()?;
    send_output(outputs.stderr, io::stdout());
    ctx.set_time_passes(true);
    ctx.eval("println!(\"41\");")?;
    let start = Instant::now();
    let output = ctx.eval("println!(\"42\");")?;
    println!("Total eval time: {}ms", start.elapsed().as_millis());
    for phase in output.phases {
        println!("  {}: {}ms", phase.name, phase.duration.as_millis());
    }
    Ok(())
}
<|endoftext|>


<commit_before>// This example uses get_sock() to find out which file descriptors c-ares
// wants us to listen on, and uses epoll() to satisfy those requirements.
extern crate c_ares;
extern crate nix;

use nix::sys::epoll::{
    epoll_create,
    epoll_ctl,
    epoll_wait,
    EpollEvent,
    EpollEventKind,
    EpollOp,
    EPOLLIN,
    EPOLLOUT,
};
use std::collections::HashSet;
use std::error::Error;
use std::os::unix::io;

fn print_a_results(result: Result<c_ares::AResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("Lookup failed with error '{}'", e.description());
        }
        Ok(a_results) => {
            println!("Successful lookup...");
            println!("Hostname: {}", a_results.hostname());
            for alias in a_results.aliases() {
                println!("{:}", alias.alias());
            }
            for address in a_results.addresses() {
                println!("{:}", address.ip_address());
            }
        }
    }
}

fn print_aaaa_results(result: Result<c_ares::AAAAResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("Lookup failed with error '{}'", e.description());
        }
        Ok(aaaa_results) => {
            println!("Successful lookup...");
            println!("Hostname: {}", aaaa_results.hostname());
            for alias in aaaa_results.aliases() {
                println!("{:}", alias.alias());
            }
            for address in aaaa_results.addresses() {
                println!("{:}", address.ip_address());
            }
        }
    }
}

fn print_srv_results(result: Result<c_ares::SRVResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("SRV lookup failed with error '{}'", e.description());
        }
        Ok(srv_results) => {
            println!("Successful SRV lookup...");
            for srv_result in &srv_results {
                println!("host: {} (port: {}), priority: {} weight: {}",
                         srv_result.host(),
                         srv_result.port(),
                         srv_result.priority(),
                         srv_result.weight());
            }
        }
    }
}

fn main() {
    // Create the c_ares::Channel.
    let mut options = c_ares::Options::new();
    options
        .set_flags(c_ares::flags::STAYOPEN)
        .set_timeout(500)
        .set_tries(3);
    let mut ares_channel = c_ares::Channel::new(options)
        .ok()
        .expect("Failed to create channel");

    // Set up some queries.
    ares_channel.query_a("apple.com", move |result| {
        println!("");
        print_a_results(result);
    });

    ares_channel.query_aaaa("google.com", move |result| {
        println!("");
        print_aaaa_results(result);
    });

    ares_channel.query_srv("_xmpp-server._tcp.gmail.com", move |result| {
        println!("");
        print_srv_results(result);
    });

    // Create an epoll file descriptor so that we can listen for events.
    let epoll = epoll_create().ok().expect("Failed to create epoll");
    let mut tracked_fds = HashSet::<io::RawFd>::new();
    loop {
        // Ask c-ares what file descriptors we should be listening on, and map
        // those requests onto the epoll file descriptor.
        let mut active = false;
        for (fd, readable, writable) in &ares_channel.get_sock() {
            let mut interest = EpollEventKind::empty();
            if readable { interest = interest | EPOLLIN; }
            if writable { interest = interest | EPOLLOUT; }
            let event = EpollEvent {
                events: interest,
                data: fd as u64,
            };
            let op = if tracked_fds.insert(fd) {
                EpollOp::EpollCtlAdd
            } else {
                EpollOp::EpollCtlMod
            };
            epoll_ctl(epoll, op, fd, &event).ok().expect("epoll_ctl failed");
            active = true;
        }
        if !active { break }

        // Wait for something to happen.
        let empty_event = EpollEvent {
            events: EpollEventKind::empty(),
            data: 0,
        };
        let mut events = [empty_event; 2];
        let results = epoll_wait(epoll, &mut events, 500)
            .ok()
            .expect("epoll_wait failed");

        // Process whatever happened.
        match results {
            0 => {
                // No events - must be a timeout.  Tell c-ares about it.
                ares_channel.process_fd(
                    c_ares::INVALID_FD,
                    c_ares::INVALID_FD);
            },
            n => {
                // Sockets became readable or writable.  Tell c-ares about it.
                for event in &events[0..n] {
                    let active_fd = event.data as io::RawFd;
                    let readable_fd = if (event.events & EPOLLIN).is_empty() {
                        c_ares::INVALID_FD
                    } else {
                        active_fd
                    };
                    let writable_fd = if (event.events & EPOLLOUT).is_empty() {
                        c_ares::INVALID_FD
                    } else {
                        active_fd
                    };
                    ares_channel.process_fd(readable_fd, writable_fd);
                }
            }
        }
    }
}
<commit_msg>Restore missing text<commit_after>// This example uses get_sock() to find out which file descriptors c-ares
// wants us to listen on, and uses epoll() to satisfy those requirements.
extern crate c_ares;
extern crate nix;

use nix::sys::epoll::{
    epoll_create,
    epoll_ctl,
    epoll_wait,
    EpollEvent,
    EpollEventKind,
    EpollOp,
    EPOLLIN,
    EPOLLOUT,
};
use std::collections::HashSet;
use std::error::Error;
use std::os::unix::io;

fn print_a_results(result: Result<c_ares::AResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("A lookup failed with error '{}'", e.description());
        }
        Ok(a_results) => {
            println!("Successful lookup...");
            println!("Hostname: {}", a_results.hostname());
            for alias in a_results.aliases() {
                println!("{:}", alias.alias());
            }
            for address in a_results.addresses() {
                println!("{:}", address.ip_address());
            }
        }
    }
}

fn print_aaaa_results(result: Result<c_ares::AAAAResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("AAAA lookup failed with error '{}'", e.description());
        }
        Ok(aaaa_results) => {
            println!("Successful lookup...");
            println!("Hostname: {}", aaaa_results.hostname());
            for alias in aaaa_results.aliases() {
                println!("{:}", alias.alias());
            }
            for address in aaaa_results.addresses() {
                println!("{:}", address.ip_address());
            }
        }
    }
}

fn print_srv_results(result: Result<c_ares::SRVResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("SRV lookup failed with error '{}'", e.description());
        }
        Ok(srv_results) => {
            println!("Successful SRV lookup...");
            for srv_result in &srv_results {
                println!("host: {} (port: {}), priority: {} weight: {}",
                         srv_result.host(),
                         srv_result.port(),
                         srv_result.priority(),
                         srv_result.weight());
            }
        }
    }
}

fn main() {
    // Create the c_ares::Channel.
    let mut options = c_ares::Options::new();
    options
        .set_flags(c_ares::flags::STAYOPEN)
        .set_timeout(500)
        .set_tries(3);
    let mut ares_channel = c_ares::Channel::new(options)
        .ok()
        .expect("Failed to create channel");

    // Set up some queries.
    ares_channel.query_a("apple.com", move |result| {
        println!("");
        print_a_results(result);
    });

    ares_channel.query_aaaa("google.com", move |result| {
        println!("");
        print_aaaa_results(result);
    });

    ares_channel.query_srv("_xmpp-server._tcp.gmail.com", move |result| {
        println!("");
        print_srv_results(result);
    });

    // Create an epoll file descriptor so that we can listen for events.
    let epoll = epoll_create().ok().expect("Failed to create epoll");
    let mut tracked_fds = HashSet::<io::RawFd>::new();
    loop {
        // Ask c-ares what file descriptors we should be listening on, and map
        // those requests onto the epoll file descriptor.
        let mut active = false;
        for (fd, readable, writable) in &ares_channel.get_sock() {
            let mut interest = EpollEventKind::empty();
            if readable { interest = interest | EPOLLIN; }
            if writable { interest = interest | EPOLLOUT; }
            let event = EpollEvent {
                events: interest,
                data: fd as u64,
            };
            let op = if tracked_fds.insert(fd) {
                EpollOp::EpollCtlAdd
            } else {
                EpollOp::EpollCtlMod
            };
            epoll_ctl(epoll, op, fd, &event).ok().expect("epoll_ctl failed");
            active = true;
        }
        if !active { break }

        // Wait for something to happen.
        let empty_event = EpollEvent {
            events: EpollEventKind::empty(),
            data: 0,
        };
        let mut events = [empty_event; 2];
        let results = epoll_wait(epoll, &mut events, 500)
            .ok()
            .expect("epoll_wait failed");

        // Process whatever happened.
        match results {
            0 => {
                // No events - must be a timeout.  Tell c-ares about it.
                ares_channel.process_fd(
                    c_ares::INVALID_FD,
                    c_ares::INVALID_FD);
            },
            n => {
                // Sockets became readable or writable.  Tell c-ares about it.
                for event in &events[0..n] {
                    let active_fd = event.data as io::RawFd;
                    let readable_fd = if (event.events & EPOLLIN).is_empty() {
                        c_ares::INVALID_FD
                    } else {
                        active_fd
                    };
                    let writable_fd = if (event.events & EPOLLOUT).is_empty() {
                        c_ares::INVALID_FD
                    } else {
                        active_fd
                    };
                    ares_channel.process_fd(readable_fd, writable_fd);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! # C API for rav1e
//!
//! [rav1e](https://github.com/xiph/rav1e/) is an [AV1](https://aomediacodec.github.io/av1-spec/)
//! encoder written in [Rust](https://rust-lang.org)
//!
//! This is the C-compatible API

extern crate rav1e;
extern crate libc;

use std::slice;
use std::sync::Arc;

use std::ffi::CStr;
use std::os::raw::c_char;
use std::os::raw::c_int;

use libc::size_t;
use libc::ptrdiff_t;

/// Raw video Frame
///
/// It can be allocated throught rav1e_frame_new(), populated using rav1e_frame_fill_plane()
/// and freed using rav1e_frame_unref().
pub struct Frame(Arc<rav1e::Frame>);

type EncoderStatus=rav1e::EncoderStatus;

/// Encoder configuration
///
/// Instantiate it using rav1e_config_default() and fine-tune it using
/// rav1e_config_parse().
///
/// Use rav1e_config_unref() to free its memory.
pub struct Config {
    cfg: rav1e::Config,
    last_err: Option<EncoderStatus>,
}

/// Encoder context
///
/// Contains the encoding state, it is created by rav1e_context_new() using an
/// Encoder configuration.
///
/// Use rav1e_context_unref() to free its memory.
pub struct Context {
    ctx: rav1e::Context,
    last_err: Option<EncoderStatus>,
}

type FrameType = rav1e::FrameType;

/// Encoded Packet
///
/// The encoded packets are retrieved using rav1e_receive_packet().
///
/// Use rav1e_packet_unref() to free its memory.
#[repr(C)]
pub struct Packet {
    /// Encoded data buffer
    pub data: *const u8,
    /// Encoded data buffer size
    pub len: size_t,
    /// Frame sequence number
    pub number: u64,
    /// Frame type
    pub frame_type: FrameType,
}

type ChromaSamplePosition=rav1e::ChromaSamplePosition;
type ChromaSampling=rav1e::ChromaSampling;
type MatrixCoefficients=rav1e::MatrixCoefficients;
type ColorPrimaries=rav1e::ColorPrimaries;
type TransferCharacteristics=rav1e::TransferCharacteristics;
type Rational=rav1e::Rational;

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_default(
    width: u32,
    height: u32,
    bit_depth: u8,
    chroma_sampling: ChromaSampling,
    chroma_sample_position: ChromaSamplePosition,
    time_base: Rational,
) -> *mut Config {
    let enc = rav1e::EncoderConfig{
      width : width as usize,
      height: height as usize,
      bit_depth: bit_depth as usize,
      chroma_sampling,
      chroma_sample_position,
      time_base,
      ..Default::default()
    };
    let cfg = rav1e::Config {
        enc
    };

    let c = Box::new(Config {
        cfg,
        last_err: None,
    });

    Box::into_raw(c)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_color_description(cfg: *mut Config,
                                                            matrix: MatrixCoefficients,
                                                            primaries: ColorPrimaries,
                                                            transfer: TransferCharacteristics)
{
    (*cfg).cfg.enc.color_description = Some(rav1e::ColorDescription {
        matrix_coefficients: matrix,
        color_primaries: primaries,
        transfer_characteristics: transfer,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_content_light(cfg: *mut Config,
                                                        max_content_light_level: u16,
                                                        max_frame_average_light_level: u16)
{
    (*cfg).cfg.enc.content_light = Some(rav1e::ContentLight {
        max_content_light_level,
        max_frame_average_light_level,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_mastering_display(cfg: *mut Config,
                                                            primaries: [rav1e::Point; 3],
                                                            white_point: rav1e::Point,
                                                            max_luminance: u32,
                                                            min_luminance: u32)
{
    (*cfg).cfg.enc.mastering_display = Some(rav1e::MasteringDisplay {
        primaries,
        white_point,
        max_luminance,
        min_luminance,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_unref(cfg: *mut Config) {
    let _ = Box::from_raw(cfg);
}

/// Set a configuration parameter using its key and value
///
/// Available keys and values
/// - "quantizer": 0-255, default 100
/// - "speed": 0-10, default 3
/// - "tune": "psnr"-"psychovisual", default "psnr"
///
/// Returns a negative value on non-zero.
#[no_mangle]
pub unsafe extern "C" fn rav1e_config_parse(
    cfg: *mut Config,
    key: *const c_char,
    value: *const c_char,
) -> c_int {
    let key = CStr::from_ptr(key).to_string_lossy();
    let value = CStr::from_ptr(value).to_string_lossy();

    (*cfg)
        .cfg
        .parse(&key, &value)
        .map(|_v| {
            (*cfg).last_err = None;
            0
        }).map_err(|e| (*cfg).last_err = Some(e))
        .unwrap_or(-1)
}

/// Generate a new encoding context from a populated encoder configuration
///
/// Multiple contexts can be generated through it.
#[no_mangle]
pub unsafe extern "C" fn rav1e_context_new(cfg: *const Config) -> *mut Context {
    let ctx = Context {
        ctx: (*cfg).cfg.new_context(),
        last_err: None,
    };

    Box::into_raw(Box::new(ctx))
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_context_unref(ctx: *mut Context) {
    let _ = Box::from_raw(ctx);
}

/// Produce a new frame from the encoding context
///
/// It must be populated using rav1e_frame_fill_plane().
///
/// The frame is reference counted and must be released passing it to rav1e_frame_unref(),
/// see rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_new(ctx: *const Context) -> *mut Frame {
    let f = (*ctx).ctx.new_frame();
    let frame = Box::new(Frame(f));

    Box::into_raw(frame)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_unref(frame: *mut Frame) {
    let _ = Arc::from_raw(frame);
}

/// Send the frame for encoding
///
/// The function increases the frame internal reference count and it can be passed multiple
/// times to different rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_send_frame(ctx: *mut Context, frame: *const Frame) -> c_int {
    let frame = if frame.is_null() {
        None
    } else {
        Some((*frame).0.clone())
    };

    (*ctx)
        .ctx
        .send_frame(frame)
        .map(|_v| {
            (*ctx).last_err = None;
            0
        }).map_err(|e| (*ctx).last_err = Some(e))
        .unwrap_or(-1)
}

/// Receive encoded data
#[no_mangle]
pub unsafe extern "C" fn rav1e_receive_packet(
    ctx: *mut Context,
    pkt: *mut *mut Packet,
) -> c_int {
    (*ctx)
        .ctx
        .receive_packet()
        .map(|p| {
            (*ctx).last_err = None;
            let packet = Packet {
                data: p.data.as_ptr(),
                len: p.data.len(),
                number: p.number,
                frame_type: p.frame_type,
            };
            *pkt = Box::into_raw(Box::new(packet));
            0
        }).map_err(|e| (*ctx).last_err = Some(e))
        .unwrap_or(-1)
}

#[no_mangle]
pub unsafe extern fn rav1e_packet_unref(pkt: *mut Packet) {
    let _ = Box::from_raw(pkt);
}

/// Produce a sequence header matching the current encoding context
///
/// Its format is compatible with the AV1 Matroska and ISOBMFF specification.
///
/// Use rav1e_container_sequence_header_unref() to free it.
#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header(ctx: *mut Context, buf_size: *mut size_t) -> *mut u8 {
    let buf = (*ctx).ctx.container_sequence_header();

    *buf_size = buf.len();
    Box::into_raw(buf.into_boxed_slice()) as *mut u8
}

#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header_unref(sequence: *mut u8) {
    let _ = Box::from_raw(sequence);
}

/// Fill a frame plane
///
/// Currently the frame contains 3 planes, the first is luminance followed by
/// chrominance.
///
/// The data is copied and this function has to be called for each plane.
///
/// frame: A frame provided by rav1e_frame_new()
/// plane: The index of the plane starting from 0
/// data: The data to be copied
/// data_len: Lenght of the buffer
/// stride: Plane line in bytes, including padding
/// bytewidth: Number of bytes per component, either 1 or 2
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_fill_plane(
    frame: *mut Frame,
    plane: c_int,
    data: *const u8,
    data_len: size_t,
    stride: ptrdiff_t,
    bytewidth: c_int,
) {
    let input = Arc::get_mut(&mut (*frame).0).unwrap();
    let data_slice = slice::from_raw_parts(data, data_len as usize);

    input.planes[plane as usize].copy_from_raw_u8(data_slice, stride as usize, bytewidth as usize);
}
<commit_msg>crav1e: Let rav1e_config_default() use defaults<commit_after>//! # C API for rav1e
//!
//! [rav1e](https://github.com/xiph/rav1e/) is an [AV1](https://aomediacodec.github.io/av1-spec/)
//! encoder written in [Rust](https://rust-lang.org)
//!
//! This is the C-compatible API

extern crate rav1e;
extern crate libc;

use std::slice;
use std::sync::Arc;

use std::ffi::CStr;
use std::os::raw::c_char;
use std::os::raw::c_int;

use libc::size_t;
use libc::ptrdiff_t;

/// Raw video Frame
///
/// It can be allocated throught rav1e_frame_new(), populated using rav1e_frame_fill_plane()
/// and freed using rav1e_frame_unref().
pub struct Frame(Arc<rav1e::Frame>);

type EncoderStatus=rav1e::EncoderStatus;

/// Encoder configuration
///
/// Instantiate it using rav1e_config_default() and fine-tune it using
/// rav1e_config_parse().
///
/// Use rav1e_config_unref() to free its memory.
pub struct Config {
    cfg: rav1e::Config,
    last_err: Option<EncoderStatus>,
}

/// Encoder context
///
/// Contains the encoding state, it is created by rav1e_context_new() using an
/// Encoder configuration.
///
/// Use rav1e_context_unref() to free its memory.
pub struct Context {
    ctx: rav1e::Context,
    last_err: Option<EncoderStatus>,
}

type FrameType = rav1e::FrameType;

/// Encoded Packet
///
/// The encoded packets are retrieved using rav1e_receive_packet().
///
/// Use rav1e_packet_unref() to free its memory.
#[repr(C)]
pub struct Packet {
    /// Encoded data buffer
    pub data: *const u8,
    /// Encoded data buffer size
    pub len: size_t,
    /// Frame sequence number
    pub number: u64,
    /// Frame type
    pub frame_type: FrameType,
}

type ChromaSamplePosition=rav1e::ChromaSamplePosition;
type ChromaSampling=rav1e::ChromaSampling;
type MatrixCoefficients=rav1e::MatrixCoefficients;
type ColorPrimaries=rav1e::ColorPrimaries;
type TransferCharacteristics=rav1e::TransferCharacteristics;
type Rational=rav1e::Rational;

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_default() -> *mut Config {
    let cfg = rav1e::Config {
        enc: rav1e::EncoderConfig::default(),
    };

    let c = Box::new(Config {
        cfg,
        last_err: None,
    });

    Box::into_raw(c)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_color_description(cfg: *mut Config,
                                                            matrix: MatrixCoefficients,
                                                            primaries: ColorPrimaries,
                                                            transfer: TransferCharacteristics)
{
    (*cfg).cfg.enc.color_description = Some(rav1e::ColorDescription {
        matrix_coefficients: matrix,
        color_primaries: primaries,
        transfer_characteristics: transfer,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_content_light(cfg: *mut Config,
                                                        max_content_light_level: u16,
                                                        max_frame_average_light_level: u16)
{
    (*cfg).cfg.enc.content_light = Some(rav1e::ContentLight {
        max_content_light_level,
        max_frame_average_light_level,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_mastering_display(cfg: *mut Config,
                                                            primaries: [rav1e::Point; 3],
                                                            white_point: rav1e::Point,
                                                            max_luminance: u32,
                                                            min_luminance: u32)
{
    (*cfg).cfg.enc.mastering_display = Some(rav1e::MasteringDisplay {
        primaries,
        white_point,
        max_luminance,
        min_luminance,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_unref(cfg: *mut Config) {
    let _ = Box::from_raw(cfg);
}

/// Set a configuration parameter using its key and value
///
/// Available keys and values
/// - "quantizer": 0-255, default 100
/// - "speed": 0-10, default 3
/// - "tune": "psnr"-"psychovisual", default "psnr"
///
/// Returns a negative value on non-zero.
#[no_mangle]
pub unsafe extern "C" fn rav1e_config_parse(
    cfg: *mut Config,
    key: *const c_char,
    value: *const c_char,
) -> c_int {
    let key = CStr::from_ptr(key).to_string_lossy();
    let value = CStr::from_ptr(value).to_string_lossy();

    (*cfg)
        .cfg
        .parse(&key, &value)
        .map(|_v| {
            (*cfg).last_err = None;
            0
        }).map_err(|e| (*cfg).last_err = Some(e))
        .unwrap_or(-1)
}

/// Generate a new encoding context from a populated encoder configuration
///
/// Multiple contexts can be generated through it.
#[no_mangle]
pub unsafe extern "C" fn rav1e_context_new(cfg: *const Config) -> *mut Context {
    let ctx = Context {
        ctx: (*cfg).cfg.new_context(),
        last_err: None,
    };

    Box::into_raw(Box::new(ctx))
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_context_unref(ctx: *mut Context) {
    let _ = Box::from_raw(ctx);
}

/// Produce a new frame from the encoding context
///
/// It must be populated using rav1e_frame_fill_plane().
///
/// The frame is reference counted and must be released passing it to rav1e_frame_unref(),
/// see rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_new(ctx: *const Context) -> *mut Frame {
    let f = (*ctx).ctx.new_frame();
    let frame = Box::new(Frame(f));

    Box::into_raw(frame)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_unref(frame: *mut Frame) {
    let _ = Arc::from_raw(frame);
}

/// Send the frame for encoding
///
/// The function increases the frame internal reference count and it can be passed multiple
/// times to different rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_send_frame(ctx: *mut Context, frame: *const Frame) -> c_int {
    let frame = if frame.is_null() {
        None
    } else {
        Some((*frame).0.clone())
    };

    (*ctx)
        .ctx
        .send_frame(frame)
        .map(|_v| {
            (*ctx).last_err = None;
            0
        }).map_err(|e| (*ctx).last_err = Some(e))
        .unwrap_or(-1)
}

/// Receive encoded data
#[no_mangle]
pub unsafe extern "C" fn rav1e_receive_packet(
    ctx: *mut Context,
    pkt: *mut *mut Packet,
) -> c_int {
    (*ctx)
        .ctx
        .receive_packet()
        .map(|p| {
            (*ctx).last_err = None;
            let packet = Packet {
                data: p.data.as_ptr(),
                len: p.data.len(),
                number: p.number,
                frame_type: p.frame_type,
            };
            *pkt = Box::into_raw(Box::new(packet));
            0
        }).map_err(|e| (*ctx).last_err = Some(e))
        .unwrap_or(-1)
}

#[no_mangle]
pub unsafe extern fn rav1e_packet_unref(pkt: *mut Packet) {
    let _ = Box::from_raw(pkt);
}

/// Produce a sequence header matching the current encoding context
///
/// Its format is compatible with the AV1 Matroska and ISOBMFF specification.
///
/// Use rav1e_container_sequence_header_unref() to free it.
#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header(ctx: *mut Context, buf_size: *mut size_t) -> *mut u8 {
    let buf = (*ctx).ctx.container_sequence_header();

    *buf_size = buf.len();
    Box::into_raw(buf.into_boxed_slice()) as *mut u8
}

#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header_unref(sequence: *mut u8) {
    let _ = Box::from_raw(sequence);
}

/// Fill a frame plane
///
/// Currently the frame contains 3 planes, the first is luminance followed by
/// chrominance.
///
/// The data is copied and this function has to be called for each plane.
///
/// frame: A frame provided by rav1e_frame_new()
/// plane: The index of the plane starting from 0
/// data: The data to be copied
/// data_len: Lenght of the buffer
/// stride: Plane line in bytes, including padding
/// bytewidth: Number of bytes per component, either 1 or 2
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_fill_plane(
    frame: *mut Frame,
    plane: c_int,
    data: *const u8,
    data_len: size_t,
    stride: ptrdiff_t,
    bytewidth: c_int,
) {
    let input = Arc::get_mut(&mut (*frame).0).unwrap();
    let data_slice = slice::from_raw_parts(data, data_len as usize);

    input.planes[plane as usize].copy_from_raw_u8(data_slice, stride as usize, bytewidth as usize);
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Yusuke Sasaki
//
// This software is released under the MIT License.
// See http://opensource.org/licenses/mit-license.php or <LICENSE>.

extern crate gurobi;
use gurobi::*;

macro_rules! def_var {
  ($model:expr, $name:ident : binary) => {
    let $name = $model.add_var(stringify!($name), Binary, 0.0, 0.0, 1.0, &[], &[]).unwrap();
  };

  ($model:expr, $name:ident : integer [$lb:expr, $ub:expr]) => {
    let $name = $model.add_var(stringify!($name), Integer, 0.0, ($lb).into(), ($ub).into(), &[], &[]).unwrap();
  };

  ($model:expr, $name:ident : real [$lb:expr, $ub:expr]) => {
    let $name = $model.add_var(stringify!($name), Continuous, 0.0, ($lb).into(), ($ub).into(), &[], &[]).unwrap();
  };

  ($model:expr, $name:ident : binary, $($t:tt)*) => {
    let $name = $model.add_var(stringify!($name), Binary, 0.0, 0.0, 1.0, &[], &[]).unwrap();
    def_var!($model, $($t)*);
  };

  ($model:expr, $name:ident : integer [$lb:expr, $ub:expr], $($t:tt)*) => {
    let $name = $model.add_var(stringify!($name), Integer, 0.0, ($lb).into(), ($ub).into(), &[], &[]).unwrap();
    def_var!($model, $($t)*);
  };

  ($model:expr, $name:ident : real [$lb:expr, $ub:expr], $($t:tt)*) => {
    let $name = $model.add_var(stringify!($name), Continuous, 0.0, ($lb).into(), ($ub).into(), &[], &[]).unwrap();
    def_var!($model, $($t)*);
  };
}

macro_rules! add_constr {
  { $model:expr, $name:ident : $lhs:tt <= $rhs:tt } => {
    $model.add_constr(stringify!($name), $lhs, Less, ($rhs).into()).unwrap();
  };

  { $model:expr, $name:ident : $lhs:tt == $rhs:tt } => {
    $model.add_constr(stringify!($name), $lhs, Equal, ($rhs).into()).unwrap();
  };

  { $model:expr, $name:ident : $lhs:tt >= $rhs:tt } => {
    $model.add_constr(stringify!($name), $lhs, Greater, ($rhs).into()).unwrap();
  };

  ($model:expr, $name:ident : $lhs:tt <= $rhs:tt, $($s:tt)*) => {
    $model.add_constr(stringify!($name), $lhs, Less, ($rhs).into()).unwrap();
    add_constr!($model, $($s)*);
  };

  ($model:expr, $name:ident : $lhs:tt == $rhs:tt, $($s:tt)*) => {
    $model.add_constr(stringify!($name), $lhs, Equal, ($rhs).into()).unwrap();
    add_constr!($model, $($s)*);
  };

  ($model:expr, $name:ident : $lhs:tt >= $rhs:tt, $($s:tt)*) => {
    $model.add_constr(stringify!($name), $lhs, Greater, ($rhs).into()).unwrap();
    add_constr!($model, $($s)*);
  };
}

macro_rules! set_objective {
  ($model:expr, expr: ($($t:tt)*), sense: $sense:ident) => {
    $model.set_objective($($t)*, $sense).unwrap();
  }
}

macro_rules! def_model {
  { env:  $env:ident,
    name: $name:expr,
    vars: { $($t:tt)* },
    objective: { $($o:tt)* },
    constrs: { $($c:tt)* }
  } => { {
    let mut model = Model::new($name, &$env).unwrap();

    def_var!(model, $($t)*);
    model.update().unwrap();

    add_constr!(model, $($c)*);
    model.update().unwrap();

    set_objective!(model, $($o)*);
    model.update().unwrap();

    model
  } }
}

fn main() {
  let env = Env::new("mip_build.log").unwrap();

  let model = def_model! {
    env: env,
    name: "mip_build",
    vars: {
      x: binary,
      y: binary,
      z: binary,
      s: integer[0, 2],
      t: real[0,10]
    },
    objective: {
      expr: (&x + &y + 2.0 * &z),
      sense: Maximize
    },
    constrs: {
      c0: (&x + 2.0 * &y + 3.0 * &z) <= 4,
      c1: (&x + &y) <= 1,
      c2: (1.0 * &s) == 0,
      c3: (1.0 * &t) == 0
    }
  };

  model.write("mip.lp").unwrap();
}
<commit_msg>refactor<commit_after>// Copyright (c) 2016 Yusuke Sasaki
//
// This software is released under the MIT License.
// See http://opensource.org/licenses/mit-license.php or <LICENSE>.

extern crate gurobi;
use gurobi::*;

macro_rules! def_var {
  ($model:expr) => ();
  ($model:expr,) => ();

  ($model:expr, $name:ident : binary, $($t:tt)*) => {
    let $name = $model.add_var(stringify!($name), Binary, 0.0, 0.0, 1.0, &[], &[]).unwrap();
    def_var!($model, $($t)*);
  };

  ($model:expr, $name:ident : integer [$lb:expr, $ub:expr], $($t:tt)*) => {
    let $name = $model.add_var(stringify!($name), Integer, 0.0, ($lb).into(), ($ub).into(), &[], &[]).unwrap();
    def_var!($model, $($t)*);
  };

  ($model:expr, $name:ident : real [$lb:expr, $ub:expr], $($t:tt)*) => {
    let $name = $model.add_var(stringify!($name), Continuous, 0.0, ($lb).into(), ($ub).into(), &[], &[]).unwrap();
    def_var!($model, $($t)*);
  };
}

macro_rules! add_constr {
  ($model:expr) => ();
  ($model:expr,) => ();

  ($model:expr, $name:ident : $lhs:tt <= $rhs:tt , $($s:tt)*) => {
    $model.add_constr(stringify!($name), ($lhs), Less, ($rhs).into()).unwrap();
    add_constr!($model, $($s)*);
  };

  ($model:expr, $name:ident : $lhs:tt == $rhs:tt , $($s:tt)*) => {
    $model.add_constr(stringify!($name), ($lhs), Equal, ($rhs).into()).unwrap();
    add_constr!($model, $($s)*);
  };

  ($model:expr, $name:ident : $lhs:tt >= $rhs:tt , $($s:tt)*) => {
    $model.add_constr(stringify!($name), ($lhs), Greater, ($rhs).into()).unwrap();
    add_constr!($model, $($s)*);
  };
}

macro_rules! set_objective {
  ($model:expr, expr: ($($t:tt)*), sense: $sense:ident) => {
    $model.set_objective($($t)*, $sense).unwrap();
  }
}

macro_rules! def_model {
  { env: $env:ident,  name: $name:expr,  vars: { $($t:tt)* },  objective: { $($o:tt)* },  constrs: { $($c:tt)* } } => { {
    let mut model = Model::new($name, &$env).unwrap();

    def_var!(model, $($t)*);
    model.update().unwrap();

    add_constr!(model, $($c)*);
    model.update().unwrap();

    set_objective!(model, $($o)*);
    model.update().unwrap();

    model
  } }
}

fn main() {
  let env = Env::new("mip_build.log").unwrap();

  let model = def_model! {
    env: env,
    name: "mip_build",
    vars: {
      x: binary,
      y: binary,
      z: binary,
      s: integer[0, 2],
      t: real[0, 10],
    },
    objective: {
      expr: (&x + &y + 2.0 * &z),
      sense: Maximize
    },
    constrs: {
      c0: (&x + 2.0 * &y + 3.0 * &z) <= 4,
      c1: (&x + &y) <= 1,
      c2: (1.0 * &s) == 0,
      c3: (1.0 * &t) == 0,
    }
  };

  model.write("mip.lp").unwrap();
}
<|endoftext|>