<commit_before>//! Global initialization and retrieval of command line arguments.
//!
//! On some platforms these are stored during runtime startup,
//! and on some they are retrieved from the system on demand.

#![allow(dead_code)] // runtime init functions not used during testing

use crate::ffi::OsString;
use crate::fmt;
use crate::vec;

/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) {
    imp::init(argc, argv)
}

/// Returns the command line arguments
pub fn args() -> Args {
    imp::args()
}

pub struct Args {
    iter: vec::IntoIter<OsString>,
}

impl !Send for Args {}
impl !Sync for Args {}

impl fmt::Debug for Args {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.iter.as_slice().fmt(f)
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> {
        self.iter.next()
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize {
        self.iter.len()
    }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> {
        self.iter.next_back()
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "android",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris",
    target_os = "illumos",
    target_os = "emscripten",
    target_os = "haiku",
    target_os = "l4re",
    target_os = "fuchsia",
    target_os = "redox",
    target_os = "vxworks"
))]
mod imp {
    use super::Args;
    use crate::ffi::{CStr, OsString};
    use crate::os::unix::prelude::*;
    use crate::ptr;
    use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};

    static ARGC: AtomicIsize = AtomicIsize::new(0);
    static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());

    unsafe fn really_init(argc: isize, argv: *const *const u8) {
        ARGC.store(argc, Ordering::Relaxed);
        ARGV.store(argv as *mut _, Ordering::Relaxed);
    }

    #[inline(always)]
    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
        // On Linux-GNU, we rely on `ARGV_INIT_ARRAY` below to initialize
        // `ARGC` and `ARGV`. But in Miri that does not actually happen so we
        // still initialize here.
        #[cfg(any(miri, not(all(target_os = "linux", target_env = "gnu"))))]
        really_init(_argc, _argv);
    }

    /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
    /// This allows `std::env::args` to work even in a `cdylib`, as it does on macOS and Windows.
    #[cfg(all(target_os = "linux", target_env = "gnu"))]
    #[used]
    #[link_section = ".init_array.00099"]
    static ARGV_INIT_ARRAY: extern "C" fn(
        crate::os::raw::c_int,
        *const *const u8,
        *const *const u8,
    ) = {
        extern "C" fn init_wrapper(
            argc: crate::os::raw::c_int,
            argv: *const *const u8,
            _envp: *const *const u8,
        ) {
            unsafe {
                really_init(argc as isize, argv);
            }
        }
        init_wrapper
    };

    pub fn args() -> Args {
        Args { iter: clone().into_iter() }
    }

    fn clone() -> Vec<OsString> {
        unsafe {
            // Load ARGC and ARGV without a lock. If the store to either ARGV or
            // ARGC isn't visible yet, we'll return an empty argument list.
            let argv = ARGV.load(Ordering::Relaxed);
            let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
            (0..argc)
                .map(|i| {
                    let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char);
                    OsStringExt::from_vec(cstr.to_bytes().to_vec())
                })
                .collect()
        }
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod imp {
    use super::Args;
    use crate::ffi::CStr;

    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}

    #[cfg(target_os = "macos")]
    pub fn args() -> Args {
        use crate::os::unix::prelude::*;
        extern "C" {
            // These functions are in crt_externs.h.
            fn _NSGetArgc() -> *mut libc::c_int;
            fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
        }

        let vec = unsafe {
            let (argc, argv) =
                (*_NSGetArgc() as isize, *_NSGetArgv() as *const *const libc::c_char);
            (0..argc as isize)
                .map(|i| {
                    let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
                    OsStringExt::from_vec(bytes)
                })
                .collect::<Vec<_>>()
        };
        Args { iter: vec.into_iter() }
    }

    // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
    // and use underscores in their names - they're most probably
    // are considered private and therefore should be avoided
    // Here is another way to get arguments using Objective C
    // runtime
    //
    // In general it looks like:
    // res = Vec::new()
    // let args = [[NSProcessInfo processInfo] arguments]
    // for i in (0..[args count])
    //      res.push([args objectAtIndex:i])
    // res
    #[cfg(target_os = "ios")]
    pub fn args() -> Args {
        use crate::ffi::OsString;
        use crate::mem;
        use crate::str;

        extern "C" {
            fn sel_registerName(name: *const libc::c_uchar) -> Sel;
            fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
        }

        #[cfg(target_arch = "aarch64")]
        extern "C" {
            fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
            #[allow(clashing_extern_declarations)]
            #[link_name = "objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
        }

        #[cfg(not(target_arch = "aarch64"))]
        extern "C" {
            fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
            #[allow(clashing_extern_declarations)]
            #[link_name = "objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
        }

        type Sel = *const libc::c_void;
        type NsId = *const libc::c_void;

        let mut res = Vec::new();

        unsafe {
            let process_info_sel = sel_registerName("processInfo\0".as_ptr());
            let arguments_sel = sel_registerName("arguments\0".as_ptr());
            let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
            let count_sel = sel_registerName("count\0".as_ptr());
            let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());

            let klass = objc_getClass("NSProcessInfo\0".as_ptr());
            let info = objc_msgSend(klass, process_info_sel);
            let args = objc_msgSend(info, arguments_sel);

            let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
            for i in 0..cnt {
                let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
                let utf_c_str: *const libc::c_char = mem::transmute(objc_msgSend(tmp, utf8_sel));
                let bytes = CStr::from_ptr(utf_c_str).to_bytes();
                res.push(OsString::from(str::from_utf8(bytes).unwrap()))
            }
        }

        Args { iter: res.into_iter() }
    }
}
<commit_msg>Rollup merge of #87279 - sunfishcode:document-unix-argv, r=RalfJung<commit_after>//! Global initialization and retrieval of command line arguments.
//!
//! On some platforms these are stored during runtime startup,
//! and on some they are retrieved from the system on demand.

#![allow(dead_code)] // runtime init functions not used during testing

use crate::ffi::OsString;
use crate::fmt;
use crate::vec;

/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) {
    imp::init(argc, argv)
}

/// Returns the command line arguments
pub fn args() -> Args {
    imp::args()
}

pub struct Args {
    iter: vec::IntoIter<OsString>,
}

impl !Send for Args {}
impl !Sync for Args {}

impl fmt::Debug for Args {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.iter.as_slice().fmt(f)
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> {
        self.iter.next()
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize {
        self.iter.len()
    }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> {
        self.iter.next_back()
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "android",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris",
    target_os = "illumos",
    target_os = "emscripten",
    target_os = "haiku",
    target_os = "l4re",
    target_os = "fuchsia",
    target_os = "redox",
    target_os = "vxworks"
))]
mod imp {
    use super::Args;
    use crate::ffi::{CStr, OsString};
    use crate::os::unix::prelude::*;
    use crate::ptr;
    use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};

    // The system-provided argc and argv, which we store in static memory
    // here so that we can defer the work of parsing them until its actually
    // needed.
    //
    // Note that we never mutate argv/argc, the argv array, or the argv
    // strings, which allows the code in this file to be very simple.
    static ARGC: AtomicIsize = AtomicIsize::new(0);
    static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());

    unsafe fn really_init(argc: isize, argv: *const *const u8) {
        // These don't need to be ordered with each other or other stores,
        // because they only hold the unmodified system-provide argv/argc.
        ARGC.store(argc, Ordering::Relaxed);
        ARGV.store(argv as *mut _, Ordering::Relaxed);
    }

    #[inline(always)]
    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
        // On Linux-GNU, we rely on `ARGV_INIT_ARRAY` below to initialize
        // `ARGC` and `ARGV`. But in Miri that does not actually happen so we
        // still initialize here.
        #[cfg(any(miri, not(all(target_os = "linux", target_env = "gnu"))))]
        really_init(_argc, _argv);
    }

    /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
    /// This allows `std::env::args` to work even in a `cdylib`, as it does on macOS and Windows.
    #[cfg(all(target_os = "linux", target_env = "gnu"))]
    #[used]
    #[link_section = ".init_array.00099"]
    static ARGV_INIT_ARRAY: extern "C" fn(
        crate::os::raw::c_int,
        *const *const u8,
        *const *const u8,
    ) = {
        extern "C" fn init_wrapper(
            argc: crate::os::raw::c_int,
            argv: *const *const u8,
            _envp: *const *const u8,
        ) {
            unsafe {
                really_init(argc as isize, argv);
            }
        }
        init_wrapper
    };

    pub fn args() -> Args {
        Args { iter: clone().into_iter() }
    }

    fn clone() -> Vec<OsString> {
        unsafe {
            // Load ARGC and ARGV, which hold the unmodified system-provided
            // argc/argv, so we can read the pointed-to memory without atomics
            // or synchronization.
            //
            // If either ARGC or ARGV is still zero or null, then either there
            // really are no arguments, or someone is asking for `args()`
            // before initialization has completed, and we return an empty
            // list.
            let argv = ARGV.load(Ordering::Relaxed);
            let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
            (0..argc)
                .map(|i| {
                    let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char);
                    OsStringExt::from_vec(cstr.to_bytes().to_vec())
                })
                .collect()
        }
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod imp {
    use super::Args;
    use crate::ffi::CStr;

    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}

    #[cfg(target_os = "macos")]
    pub fn args() -> Args {
        use crate::os::unix::prelude::*;
        extern "C" {
            // These functions are in crt_externs.h.
            fn _NSGetArgc() -> *mut libc::c_int;
            fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
        }

        let vec = unsafe {
            let (argc, argv) =
                (*_NSGetArgc() as isize, *_NSGetArgv() as *const *const libc::c_char);
            (0..argc as isize)
                .map(|i| {
                    let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
                    OsStringExt::from_vec(bytes)
                })
                .collect::<Vec<_>>()
        };
        Args { iter: vec.into_iter() }
    }

    // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
    // and use underscores in their names - they're most probably
    // are considered private and therefore should be avoided
    // Here is another way to get arguments using Objective C
    // runtime
    //
    // In general it looks like:
    // res = Vec::new()
    // let args = [[NSProcessInfo processInfo] arguments]
    // for i in (0..[args count])
    //      res.push([args objectAtIndex:i])
    // res
    #[cfg(target_os = "ios")]
    pub fn args() -> Args {
        use crate::ffi::OsString;
        use crate::mem;
        use crate::str;

        extern "C" {
            fn sel_registerName(name: *const libc::c_uchar) -> Sel;
            fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
        }

        #[cfg(target_arch = "aarch64")]
        extern "C" {
            fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
            #[allow(clashing_extern_declarations)]
            #[link_name = "objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
        }

        #[cfg(not(target_arch = "aarch64"))]
        extern "C" {
            fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
            #[allow(clashing_extern_declarations)]
            #[link_name = "objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
        }

        type Sel = *const libc::c_void;
        type NsId = *const libc::c_void;

        let mut res = Vec::new();

        unsafe {
            let process_info_sel = sel_registerName("processInfo\0".as_ptr());
            let arguments_sel = sel_registerName("arguments\0".as_ptr());
            let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
            let count_sel = sel_registerName("count\0".as_ptr());
            let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());

            let klass = objc_getClass("NSProcessInfo\0".as_ptr());
            let info = objc_msgSend(klass, process_info_sel);
            let args = objc_msgSend(info, arguments_sel);

            let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
            for i in 0..cnt {
                let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
                let utf_c_str: *const libc::c_char = mem::transmute(objc_msgSend(tmp, utf8_sel));
                let bytes = CStr::from_ptr(utf_c_str).to_bytes();
                res.push(OsString::from(str::from_utf8(bytes).unwrap()))
            }
        }

        Args { iter: res.into_iter() }
    }
}
<|endoftext|>


<commit_before>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

#[derive(Debug, PartialEq)]
pub enum Value {
    Nil,
    Boolean(bool),
    Number(f64),
    String(String),
}

#[derive(Debug)]
pub enum RuntimeError {
    RuntimeError,
}

pub trait Interpret {
    fn interpret(&self) -> Result<Value, RuntimeError>;
}

impl Interpret for Expr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Expr::Literal(ref l) => l.interpret(),
            &Expr::Unary(ref u) => unimplemented!(),
            &Expr::Binary(ref b) => unimplemented!(),
            &Expr::Grouping(ref g) => g.interpret(),
        }
    }
}

impl Interpret for Literal {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Literal::NilLiteral => Ok(Value::Nil),
            &Literal::BoolLiteral(b) => Ok(Value::Boolean(b)),
            &Literal::StringLiteral(ref s) => Ok(Value::String(s.clone())),
            &Literal::NumberLiteral(n) => Ok(Value::Number(n)),
        }
    }
}

impl Interpret for Grouping {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        self.expr.interpret()
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use interpreter::{Interpret, Value};

    #[test]
    fn literal() {
        let expr = Expr::Literal(Literal::StringLiteral("abc".into()));
        assert_eq!(Value::String("abc".into()), expr.interpret().unwrap());
    }

    #[test]
    fn grouping() {
        let expr = Grouping { expr: Expr::Literal(Literal::NumberLiteral(45.67f64)) };
        assert_eq!(Value::Number(45.67f64), expr.interpret().unwrap());
    }
}
<commit_msg>Interpret for unary expressions<commit_after>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

#[derive(Debug, PartialEq)]
pub enum Value {
    Nil,
    Boolean(bool),
    Number(f64),
    String(String),
}

impl Value {
    fn is_true(&self) -> bool {
        match self {
            &Value::Nil => false,
            &Value::Boolean(b) => b,
            _ => true,
        }
    }
}

#[derive(Debug)]
pub enum RuntimeError {
    RuntimeError,
}

pub trait Interpret {
    fn interpret(&self) -> Result<Value, RuntimeError>;
}

impl Interpret for Expr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Expr::Literal(ref l) => l.interpret(),
            &Expr::Unary(ref u) => u.interpret(),
            &Expr::Binary(ref b) => unimplemented!(),
            &Expr::Grouping(ref g) => g.interpret(),
        }
    }
}

impl Interpret for Literal {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Literal::NilLiteral => Ok(Value::Nil),
            &Literal::BoolLiteral(b) => Ok(Value::Boolean(b)),
            &Literal::StringLiteral(ref s) => Ok(Value::String(s.clone())),
            &Literal::NumberLiteral(n) => Ok(Value::Number(n)),
        }
    }
}

impl Interpret for Grouping {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        self.expr.interpret()
    }
}

impl Interpret for UnaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let value = try!(self.right.interpret());
        match self.operator {
            UnaryOperator::Bang => Ok(Value::Boolean(!value.is_true())),
            UnaryOperator::Minus => {
                match value {
                    Value::Number(n) => Ok(Value::Number(-n)),
                    _ => Err(RuntimeError::RuntimeError),
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use interpreter::{Interpret, Value};

    #[test]
    fn literal() {
        let expr = Expr::Literal(Literal::StringLiteral("abc".into()));
        assert_eq!(Value::String("abc".into()), expr.interpret().unwrap());
    }

    #[test]
    fn grouping() {
        let expr = Grouping { expr: Expr::Literal(Literal::NumberLiteral(45.67f64)) };
        assert_eq!(Value::Number(45.67f64), expr.interpret().unwrap());
    }

    #[test]
    fn unary() {
        let expr = UnaryExpr {
            operator: UnaryOperator::Bang,
            right: Expr::Literal(Literal::BoolLiteral(false)),
        };
        assert_eq!(Value::Boolean(true), expr.interpret().unwrap());
    }

}
<|endoftext|>


<commit_before>use clap::{IntoApp, Parser, Subcommand};
use clap_complete;
use cmd_queue::{constants, error::CmdqClientError, CommandRequest, CommandResponse};
use reqwest;

#[derive(Parser, Debug)]
#[clap(name = "Command Queue")]
#[clap(author = "Jonathan Fok kan <jonathan@fokkan.ca>")]
#[clap(version = "1.0")]
#[clap(about = "A program to queue commands", long_about = None)]
struct Cli {
    #[clap(help = "command to queue")]
    pub input: Vec<String>,

    #[clap(subcommand)]
    pub subcommands: Option<Subcommands>,
}

#[derive(Subcommand, Debug)]
enum Subcommands {
    /// Download with yt-dlp
    Ytdlp {
        url: String,
        #[clap(long, short, help = "Optional prefix to filename downloaded")]
        prefix: Option<String>,
    },
    /// Shutdown server daemon
    Shutdown {
        #[clap(long, short, help = "Force shutdown of cmdq server")]
        force: bool,
    },
    GenerateCompletion {
        #[clap(arg_enum)]
        shell: clap_complete::Shell,
    },
}

fn main() -> Result<(), CmdqClientError> {
    let cli = Cli::parse();
    println!("{:?}", cli);
    let cwd = std::env::current_dir().expect("current dir");

    if !cli.input.is_empty() && cli.subcommands.is_some() {
        println!("Sorry, but I don't know what to do both INPUT and subcommand were encountered. Going to sleep instead.");
        Ok(())
    } else if let Some(subcommand) = cli.subcommands {
        match subcommand {
            Subcommands::Ytdlp { url, prefix } => {
                let args = if let Some(prefix) = prefix {
                    vec![
                        "-o".to_string(),
                        format!("{} %(title)s [%(id)s].%(ext)s", prefix),
                        url,
                    ]
                } else {
                    vec![url]
                };
                command_request(&cwd.to_string_lossy(), "yt-dlp", args)
            }
            Subcommands::Shutdown { force } => shutdown_server(),
            Subcommands::GenerateCompletion { shell } => {
                print_completions(shell, &mut Cli::command_for_update());
                Ok(())
            }
        }
    } else if !cli.input.is_empty() {
        command_request(
            &cwd.to_string_lossy(),
            &cli.input[0],
            cli.input.clone().into_iter().skip(1).collect(),
        )
    } else {
        println!("no command queued");
        Ok(())
    }
}

fn print_completions<G: clap_complete::Generator>(gen: G, cmd: &mut clap::Command) {
    clap_complete::generate(gen, cmd, cmd.get_name().to_string(), &mut std::io::stdout());
}

fn command_request(cwd: &str, program: &str, args: Vec<String>) -> Result<(), CmdqClientError> {
    start_server_if_needed().expect("failed to start server");

    let client = reqwest::blocking::Client::new();
    let response = client
        .post(server_host("commands/"))
        .json(&CommandRequest {
            path: cwd.to_string(),
            program: program.to_string(),
            args: args,
        })
        .send()
        .map_err(|e| CmdqClientError::HttpClientError(e))?;
    println!("{:?}", response);
    let cmd_response = response
        .json::<CommandResponse>()
        .map_err(|e| CmdqClientError::ResponseDeserializationError(e))?;
    Ok(())
}

fn start_server_if_needed() -> std::io::Result<()> {
    let resp = reqwest::blocking::get(server_host("health"));
    if resp.is_err() {
        std::process::Command::new("cmdq_server").spawn()?;
        // TODO better handling of waiting for server to startup
        // Continue to poll health endpoint with max attempts and backoff
        std::thread::sleep(std::time::Duration::from_secs(2));
    }
    Ok(())
}

fn shutdown_server() -> Result<(), CmdqClientError> {
    use nix::sys::signal::{self, Signal};
    use nix::unistd::Pid;
    use std::fs;
    let pid_str = fs::read_to_string(constants::SERVER_DAEMON_PIDFILE).map_err(|e| {
        CmdqClientError::ReadServerPidFile(constants::SERVER_DAEMON_PIDFILE.to_string(), e)
    })?;
    let pid = pid_str
        .parse::<i32>()
        .map_err(|e| CmdqClientError::ParseServerPid(e))?;
    signal::kill(Pid::from_raw(pid), Signal::SIGINT)
        .map_err(|e| CmdqClientError::KillServer(pid, e))?;
    Ok(())
}

fn server_host(path: &str) -> String {
    format!("http://localhost:{}/{}", constants::DEFAULT_PORT, path)
}
<commit_msg>cmd-queue: removed print for shell completion<commit_after>use clap::{IntoApp, Parser, Subcommand};
use clap_complete;
use cmd_queue::{constants, error::CmdqClientError, CommandRequest, CommandResponse};
use reqwest;

#[derive(Parser, Debug)]
#[clap(name = "Command Queue")]
#[clap(author = "Jonathan Fok kan <jonathan@fokkan.ca>")]
#[clap(version = "1.0")]
#[clap(about = "A program to queue commands", long_about = None)]
struct Cli {
    #[clap(help = "command to queue")]
    pub input: Vec<String>,

    #[clap(subcommand)]
    pub subcommands: Option<Subcommands>,
}

#[derive(Subcommand, Debug)]
enum Subcommands {
    /// Download with yt-dlp
    Ytdlp {
        url: String,
        #[clap(long, short, help = "Optional prefix to filename downloaded")]
        prefix: Option<String>,
    },
    /// Shutdown server daemon
    Shutdown {
        #[clap(long, short, help = "Force shutdown of cmdq server")]
        force: bool,
    },
    GenerateCompletion {
        #[clap(arg_enum)]
        shell: clap_complete::Shell,
    },
}

fn main() -> Result<(), CmdqClientError> {
    let cli = Cli::parse();
    //println!("{:?}", cli);
    let cwd = std::env::current_dir().expect("current dir");

    if !cli.input.is_empty() && cli.subcommands.is_some() {
        println!("Sorry, but I don't know what to do both INPUT and subcommand were encountered. Going to sleep instead.");
        Ok(())
    } else if let Some(subcommand) = cli.subcommands {
        match subcommand {
            Subcommands::Ytdlp { url, prefix } => {
                let args = if let Some(prefix) = prefix {
                    vec![
                        "-o".to_string(),
                        format!("{} %(title)s [%(id)s].%(ext)s", prefix),
                        url,
                    ]
                } else {
                    vec![url]
                };
                command_request(&cwd.to_string_lossy(), "yt-dlp", args)
            }
            Subcommands::Shutdown { force } => shutdown_server(),
            Subcommands::GenerateCompletion { shell } => {
                print_completions(shell, &mut Cli::command_for_update());
                Ok(())
            }
        }
    } else if !cli.input.is_empty() {
        command_request(
            &cwd.to_string_lossy(),
            &cli.input[0],
            cli.input.clone().into_iter().skip(1).collect(),
        )
    } else {
        println!("no command queued");
        Ok(())
    }
}

fn print_completions<G: clap_complete::Generator>(gen: G, cmd: &mut clap::Command) {
    clap_complete::generate(gen, cmd, cmd.get_name().to_string(), &mut std::io::stdout());
}

fn command_request(cwd: &str, program: &str, args: Vec<String>) -> Result<(), CmdqClientError> {
    start_server_if_needed().expect("failed to start server");

    let client = reqwest::blocking::Client::new();
    let response = client
        .post(server_host("commands/"))
        .json(&CommandRequest {
            path: cwd.to_string(),
            program: program.to_string(),
            args: args,
        })
        .send()
        .map_err(|e| CmdqClientError::HttpClientError(e))?;
    println!("{:?}", response);
    let cmd_response = response
        .json::<CommandResponse>()
        .map_err(|e| CmdqClientError::ResponseDeserializationError(e))?;
    Ok(())
}

fn start_server_if_needed() -> std::io::Result<()> {
    let resp = reqwest::blocking::get(server_host("health"));
    if resp.is_err() {
        std::process::Command::new("cmdq_server").spawn()?;
        // TODO better handling of waiting for server to startup
        // Continue to poll health endpoint with max attempts and backoff
        std::thread::sleep(std::time::Duration::from_secs(2));
    }
    Ok(())
}

fn shutdown_server() -> Result<(), CmdqClientError> {
    use nix::sys::signal::{self, Signal};
    use nix::unistd::Pid;
    use std::fs;
    let pid_str = fs::read_to_string(constants::SERVER_DAEMON_PIDFILE).map_err(|e| {
        CmdqClientError::ReadServerPidFile(constants::SERVER_DAEMON_PIDFILE.to_string(), e)
    })?;
    let pid = pid_str
        .parse::<i32>()
        .map_err(|e| CmdqClientError::ParseServerPid(e))?;
    signal::kill(Pid::from_raw(pid), Signal::SIGINT)
        .map_err(|e| CmdqClientError::KillServer(pid, e))?;
    Ok(())
}

fn server_host(path: &str) -> String {
    format!("http://localhost:{}/{}", constants::DEFAULT_PORT, path)
}
<|endoftext|>


<commit_before>use input::Input;
use buffer::Direction;
use keyboard::Key;
use view::View;
use frontends::{Frontend, EditorEvent};
use modes::Mode;
use overlay::{Overlay, OverlayType, OverlayEvent};

use command::Command as Cmd;
use command::{Action, BuilderEvent, Operation, Instruction};

use textobject::{TextObject, Kind, Offset};

#[derive(Copy, Debug, PartialEq, Eq)]
pub enum Command {
    SaveBuffer,
    ExitEditor,

    MoveCursor(Direction, usize),
    LineEnd,
    LineStart,

    Delete(Direction, usize),
    InsertTab,
    InsertChar(char),

    SetOverlay(OverlayType),

    Undo,
    Redo,

    Unknown,
    None,
}

impl Command {
    #[inline]
    pub fn from_str(string: &str) -> Command {
        match string {
            "q" | "quit"  => Command::ExitEditor,
            "w" | "write" => Command::SaveBuffer,

            _             => Command::Unknown,
        }
    }
}

/// The main Editor structure
///
/// This is the top-most structure in Iota.
pub struct Editor<'e, T: Frontend> {
    view: View<'e>,
    running: bool,
    frontend: T,
    mode: Box<Mode + 'e>,
}

impl<'e, T: Frontend> Editor<'e, T> {
    /// Create a new Editor instance
    pub fn new(source: Input, mode: Box<Mode + 'e>, frontend: T) -> Editor<'e, T> {
        let height = frontend.get_window_height();
        let width = frontend.get_window_width();
        let view = View::new(source, width, height);

        Editor {
            view: view,
            running: true,
            frontend: frontend,
            mode: mode,
        }
    }

    /// Handle key events
    ///
    /// Key events can be handled in an Overlay, OR in the current Mode.
    ///
    /// If there is an active Overlay, the key event is sent there, which gives
    /// back an OverlayEvent. We then parse this OverlayEvent and determine if
    /// the Overlay is finished and can be cleared. The response from the
    /// Overlay is then converted to a Command and sent off to be handled.
    ///
    /// If there is no active Overlay, the key event is sent to the current
    /// Mode, which returns a Command which we dispatch to handle_command.
    fn handle_key_event(&mut self, key: Option<Key>) {
        let key = match key {
            Some(k) => k,
            None => return
        };

        let mut remove_overlay = false;
        let command = match self.view.overlay {
            Overlay::None => self.mode.handle_key_event(key),
            _             => {
                let event = self.view.overlay.handle_key_event(key);
                match event {
                    OverlayEvent::Finished(response) => {
                        remove_overlay = true;
                        self.handle_overlay_response(response)
                    }

                    _ => { BuilderEvent::Incomplete }
                }
            }
        };

        if remove_overlay {
            self.view.overlay = Overlay::None;
            self.view.clear(&mut self.frontend);
        }

        if let BuilderEvent::Complete(c) = command {
            self.handle_command(c);
        }
    }

    /// Translate the response from an Overlay to a Command
    ///
    /// In most cases, we will just want to convert the response directly to
    /// a Command, however in some cases we will want to perform other actions
    /// first, such as in the case of Overlay::SavePrompt.
    fn handle_overlay_response(&mut self, response: Option<String>) -> BuilderEvent {
        // FIXME: This entire method neext to be updated
        match response {
            Some(data) => {
                match self.view.overlay {

                    // FIXME: this is just a temporary fix
                    Overlay::Prompt { .. } => {
                        match Command::from_str(&*data) {
                            Command::ExitEditor => {
                                return BuilderEvent::Complete(Cmd {
                                    action:Action::Instruction(Instruction::ExitEditor),
                                    number: 0,
                                    object: TextObject {
                                        kind: Kind::Char,
                                        offset: Offset::Absolute(0),
                                    },
                                })
                            }
                            _ => BuilderEvent::Incomplete
                        }
                    }

                    Overlay::SavePrompt { .. } => {
                        let path = Path::new(&*data);
                        self.view.buffer.file_path = Some(path);
                        // Command::SaveBuffer
                        BuilderEvent::Complete(Cmd {
                            action:Action::Instruction(Instruction::SaveBuffer),
                            number: 0,
                            object: TextObject {
                                kind: Kind::Char,
                                offset: Offset::Absolute(0),
                            },
                        })
                    }
                    _ => BuilderEvent::Incomplete,
                }
            }
            None => BuilderEvent::Incomplete
        }
    }

    /// Handle resize events
    ///
    /// width and height represent the new height of the window.
    fn handle_resize_event(&mut self, width: usize, height: usize) {
        self.view.resize(width, height);
    }

    /// Draw the current view to the frontend
    fn draw(&mut self) {
        self.view.draw(&mut self.frontend);
    }

    /// Handle the given command, performing the associated action
    fn handle_command(&mut self, command: Cmd) {
        match command.action {
            Action::Instruction(i) => self.handle_instruction(i, command),
            Action::Operation(o) => self.handle_operation(o, command),
        }

        // match command {
        //     // Editor Commands
        //     Command::SaveBuffer         => self.view.try_save_buffer(),
        //     Command::SetOverlay(o)      => self.view.set_overlay(o),

        //     // Navigation
        //     Command::MoveCursor(dir, n) => self.view.move_cursor(dir, n),
        //     Command::LineEnd            => self.view.move_cursor_to_line_end(),
        //     Command::LineStart          => self.view.move_cursor_to_line_start(),

        //     // Editing
        //     Command::Delete(dir, n)     => self.view.delete_chars(dir, n),
        //     Command::InsertTab          => self.view.insert_tab(),
        //     Command::InsertChar(c)      => self.view.insert_char(c),
        //     Command::Redo               => self.view.redo(),
        //     Command::Undo               => self.view.undo(),

        //     _ => {},
        // }
    }

    fn handle_instruction(&mut self, instruction: Instruction, command: Cmd) {
        match instruction {
            Instruction::SaveBuffer => { self.view.try_save_buffer() }
            Instruction::ExitEditor => { self.running = false; }
            Instruction::SetMark(mark) => {
                let (mut dir, n) = match command.object.offset {
                    Offset::Backward(n, _) => (Direction::Left, n),
                    Offset::Forward(n, _) => (Direction::Right, n),

                    // FIXME
                    Offset::Absolute(n) => (Direction::Right, 0)
                };

                if let Kind::Line(_) = command.object.kind {
                    if dir == Direction::Left {
                        dir = Direction::Up
                    } else {
                        dir = Direction::Down
                    }
                }

                self.view.move_cursor(dir, n)
            }
            Instruction::SetOverlay(overlay_type) => {
                self.view.set_overlay(overlay_type)
            }
        }
    }

    fn handle_operation(&mut self, operation: Operation, command: Cmd) {
        match operation {
            Operation::Insert(c) => { self.view.insert_char(c) }
            Operation::Delete => {
                // FIXME: update to delete lines
                let obj = command.object;

                let (dir, n) = match obj.offset {
                    Offset::Forward(n, _) => (Direction::Right, n),
                    Offset::Backward(n, _) => (Direction::Left, n),

                    Offset::Absolute(n) => (Direction::Right, 0),
                };

                self.view.delete_chars(dir, n)
            }
            Operation::Undo => { self.view.undo() }
            Operation::Redo => { self.view.redo() }
        }
    }

    /// Start Iota!
    pub fn start(&mut self) {
        while self.running {
            self.draw();
            self.frontend.present();
            let event = self.frontend.poll_event();

            match event {
                EditorEvent::KeyEvent(key)         => self.handle_key_event(key),
                EditorEvent::Resize(width, height) => self.handle_resize_event(width, height),

                _ => {}
            }
        }
    }
}
<commit_msg>Remove commented lines which have been re-implemented in new system<commit_after>use input::Input;
use buffer::Direction;
use keyboard::Key;
use view::View;
use frontends::{Frontend, EditorEvent};
use modes::Mode;
use overlay::{Overlay, OverlayType, OverlayEvent};

use command::Command as Cmd;
use command::{Action, BuilderEvent, Operation, Instruction};

use textobject::{TextObject, Kind, Offset};

#[derive(Copy, Debug, PartialEq, Eq)]
pub enum Command {
    SaveBuffer,
    ExitEditor,

    MoveCursor(Direction, usize),
    LineEnd,
    LineStart,

    Delete(Direction, usize),
    InsertTab,
    InsertChar(char),

    SetOverlay(OverlayType),

    Undo,
    Redo,

    Unknown,
    None,
}

impl Command {
    #[inline]
    pub fn from_str(string: &str) -> Command {
        match string {
            "q" | "quit"  => Command::ExitEditor,
            "w" | "write" => Command::SaveBuffer,

            _             => Command::Unknown,
        }
    }
}

/// The main Editor structure
///
/// This is the top-most structure in Iota.
pub struct Editor<'e, T: Frontend> {
    view: View<'e>,
    running: bool,
    frontend: T,
    mode: Box<Mode + 'e>,
}

impl<'e, T: Frontend> Editor<'e, T> {
    /// Create a new Editor instance
    pub fn new(source: Input, mode: Box<Mode + 'e>, frontend: T) -> Editor<'e, T> {
        let height = frontend.get_window_height();
        let width = frontend.get_window_width();
        let view = View::new(source, width, height);

        Editor {
            view: view,
            running: true,
            frontend: frontend,
            mode: mode,
        }
    }

    /// Handle key events
    ///
    /// Key events can be handled in an Overlay, OR in the current Mode.
    ///
    /// If there is an active Overlay, the key event is sent there, which gives
    /// back an OverlayEvent. We then parse this OverlayEvent and determine if
    /// the Overlay is finished and can be cleared. The response from the
    /// Overlay is then converted to a Command and sent off to be handled.
    ///
    /// If there is no active Overlay, the key event is sent to the current
    /// Mode, which returns a Command which we dispatch to handle_command.
    fn handle_key_event(&mut self, key: Option<Key>) {
        let key = match key {
            Some(k) => k,
            None => return
        };

        let mut remove_overlay = false;
        let command = match self.view.overlay {
            Overlay::None => self.mode.handle_key_event(key),
            _             => {
                let event = self.view.overlay.handle_key_event(key);
                match event {
                    OverlayEvent::Finished(response) => {
                        remove_overlay = true;
                        self.handle_overlay_response(response)
                    }

                    _ => { BuilderEvent::Incomplete }
                }
            }
        };

        if remove_overlay {
            self.view.overlay = Overlay::None;
            self.view.clear(&mut self.frontend);
        }

        if let BuilderEvent::Complete(c) = command {
            self.handle_command(c);
        }
    }

    /// Translate the response from an Overlay to a Command
    ///
    /// In most cases, we will just want to convert the response directly to
    /// a Command, however in some cases we will want to perform other actions
    /// first, such as in the case of Overlay::SavePrompt.
    fn handle_overlay_response(&mut self, response: Option<String>) -> BuilderEvent {
        // FIXME: This entire method neext to be updated
        match response {
            Some(data) => {
                match self.view.overlay {

                    // FIXME: this is just a temporary fix
                    Overlay::Prompt { .. } => {
                        match Command::from_str(&*data) {
                            Command::ExitEditor => {
                                return BuilderEvent::Complete(Cmd {
                                    action:Action::Instruction(Instruction::ExitEditor),
                                    number: 0,
                                    object: TextObject {
                                        kind: Kind::Char,
                                        offset: Offset::Absolute(0),
                                    },
                                })
                            }
                            _ => BuilderEvent::Incomplete
                        }
                    }

                    Overlay::SavePrompt { .. } => {
                        let path = Path::new(&*data);
                        self.view.buffer.file_path = Some(path);
                        // Command::SaveBuffer
                        BuilderEvent::Complete(Cmd {
                            action:Action::Instruction(Instruction::SaveBuffer),
                            number: 0,
                            object: TextObject {
                                kind: Kind::Char,
                                offset: Offset::Absolute(0),
                            },
                        })
                    }
                    _ => BuilderEvent::Incomplete,
                }
            }
            None => BuilderEvent::Incomplete
        }
    }

    /// Handle resize events
    ///
    /// width and height represent the new height of the window.
    fn handle_resize_event(&mut self, width: usize, height: usize) {
        self.view.resize(width, height);
    }

    /// Draw the current view to the frontend
    fn draw(&mut self) {
        self.view.draw(&mut self.frontend);
    }

    /// Handle the given command, performing the associated action
    fn handle_command(&mut self, command: Cmd) {
        match command.action {
            Action::Instruction(i) => self.handle_instruction(i, command),
            Action::Operation(o) => self.handle_operation(o, command),
        }

        // TODO: re-implement these with the command/builder system
        // match command {
        //     Command::LineEnd            => self.view.move_cursor_to_line_end(),
        //     Command::LineStart          => self.view.move_cursor_to_line_start(),
        //     Command::InsertTab          => self.view.insert_tab(),
        // }
    }

    fn handle_instruction(&mut self, instruction: Instruction, command: Cmd) {
        match instruction {
            Instruction::SaveBuffer => { self.view.try_save_buffer() }
            Instruction::ExitEditor => { self.running = false; }
            Instruction::SetMark(mark) => {
                let (mut dir, n) = match command.object.offset {
                    Offset::Backward(n, _) => (Direction::Left, n),
                    Offset::Forward(n, _) => (Direction::Right, n),

                    // FIXME
                    Offset::Absolute(n) => (Direction::Right, 0)
                };

                if let Kind::Line(_) = command.object.kind {
                    if dir == Direction::Left {
                        dir = Direction::Up
                    } else {
                        dir = Direction::Down
                    }
                }

                self.view.move_cursor(dir, n)
            }
            Instruction::SetOverlay(overlay_type) => {
                self.view.set_overlay(overlay_type)
            }
        }
    }

    fn handle_operation(&mut self, operation: Operation, command: Cmd) {
        match operation {
            Operation::Insert(c) => { self.view.insert_char(c) }
            Operation::Delete => {
                // FIXME: update to delete lines
                let obj = command.object;

                let (dir, n) = match obj.offset {
                    Offset::Forward(n, _) => (Direction::Right, n),
                    Offset::Backward(n, _) => (Direction::Left, n),

                    Offset::Absolute(n) => (Direction::Right, 0),
                };

                self.view.delete_chars(dir, n)
            }
            Operation::Undo => { self.view.undo() }
            Operation::Redo => { self.view.redo() }
        }
    }

    /// Start Iota!
    pub fn start(&mut self) {
        while self.running {
            self.draw();
            self.frontend.present();
            let event = self.frontend.poll_event();

            match event {
                EditorEvent::KeyEvent(key)         => self.handle_key_event(key),
                EditorEvent::Resize(width, height) => self.handle_resize_event(width, height),

                _ => {}
            }
        }
    }
}
<|endoftext|>


<commit_before>pub mod config;

pub use config::Config;

use heck::SnakeCase;
use lucet_module::bindings::Bindings;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};

pub fn hostcall_name(m: &witx::Module, f: &witx::InterfaceFunc) -> String {
    format!(
        "hostcall_{}_{}",
        m.name.as_str().to_snake_case(),
        f.name.as_str().to_snake_case()
    )
}
pub fn bindings(doc: &witx::Document) -> Bindings {
    let bs = doc
        .modules()
        .map(|m| {
            (
                m.name.as_str().to_owned(),
                m.funcs()
                    .map(|f| (f.name.as_str().to_owned(), hostcall_name(&m, &f)))
                    .collect(),
            )
        })
        .collect();
    Bindings::new(bs)
}

pub fn generate(doc: &witx::Document, config: &Config) -> TokenStream {
    let names = wiggle_generate::Names::new(&config.wiggle);
    let fs = doc.modules().map(|m| {
        let fs = m.funcs().map(|f| {
            let name = format_ident!("{}", hostcall_name(&m, &f));
            let coretype = f.core_type();
            let func_args = coretype.args.iter().map(|a| {
                let name = names.func_core_arg(a);
                let atom = names.atom_type(a.repr());
                quote!(#name: #atom)
            });
            let call_args = coretype.args.iter().map(|a| {
                let name = names.func_core_arg(a);
                quote!(#name)
            });
            let rets = coretype
                .ret
                .as_ref()
                .map(|r| {
                    let atom = names.atom_type(r.repr());
                    quote!(#atom)
                })
                .unwrap_or(quote!(()));
            let mod_name = names.module(&m.name);
            let method_name = names.func(&f.name);
            let ctx_type = config.wiggle.ctx.name.clone();
            let ctx_constructor = config.constructor.clone();
            quote! {
                #[lucet_hostcall]
                #[no_mangle]
                pub fn #name(vmctx: &mut lucet_runtime::vmctx::Vmctx, #(#func_args),*) -> #rets {
                    let memory= lucet_wiggle_runtime::LucetMemory::new(vmctx);
                    let mut ctx: #ctx_type = #ctx_constructor;
                    #mod_name::#method_name(&ctx, &memory, #(#call_args),*)
                }
            }
        });
        quote!(#(#fs)*)
    });

    let init = doc.modules().map(|m| {
        let fs = m.funcs().map(|f| {
            let name = format_ident!("{}", hostcall_name(&m, &f));
            quote!(#name as _)
        });
        quote!(#(#fs),*)
    });

    quote! {
        use lucet_runtime::lucet_hostcall;
        #(#fs)*
        pub fn init() {
            let funcs: &[*const extern "C" fn()] = &[
                #(#init),*
            ];
            ::std::mem::forget(::std::rc::Rc::new(funcs));
        }
    }
}
<commit_msg>doc comment for init()<commit_after>pub mod config;

pub use config::Config;

use heck::SnakeCase;
use lucet_module::bindings::Bindings;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};

pub fn hostcall_name(m: &witx::Module, f: &witx::InterfaceFunc) -> String {
    format!(
        "hostcall_{}_{}",
        m.name.as_str().to_snake_case(),
        f.name.as_str().to_snake_case()
    )
}
pub fn bindings(doc: &witx::Document) -> Bindings {
    let bs = doc
        .modules()
        .map(|m| {
            (
                m.name.as_str().to_owned(),
                m.funcs()
                    .map(|f| (f.name.as_str().to_owned(), hostcall_name(&m, &f)))
                    .collect(),
            )
        })
        .collect();
    Bindings::new(bs)
}

pub fn generate(doc: &witx::Document, config: &Config) -> TokenStream {
    let names = wiggle_generate::Names::new(&config.wiggle);
    let fs = doc.modules().map(|m| {
        let fs = m.funcs().map(|f| {
            let name = format_ident!("{}", hostcall_name(&m, &f));
            let coretype = f.core_type();
            let func_args = coretype.args.iter().map(|a| {
                let name = names.func_core_arg(a);
                let atom = names.atom_type(a.repr());
                quote!(#name: #atom)
            });
            let call_args = coretype.args.iter().map(|a| {
                let name = names.func_core_arg(a);
                quote!(#name)
            });
            let rets = coretype
                .ret
                .as_ref()
                .map(|r| {
                    let atom = names.atom_type(r.repr());
                    quote!(#atom)
                })
                .unwrap_or(quote!(()));
            let mod_name = names.module(&m.name);
            let method_name = names.func(&f.name);
            let ctx_type = config.wiggle.ctx.name.clone();
            let ctx_constructor = config.constructor.clone();
            quote! {
                #[lucet_hostcall]
                #[no_mangle]
                pub fn #name(vmctx: &mut lucet_runtime::vmctx::Vmctx, #(#func_args),*) -> #rets {
                    let memory= lucet_wiggle_runtime::LucetMemory::new(vmctx);
                    let mut ctx: #ctx_type = #ctx_constructor;
                    #mod_name::#method_name(&ctx, &memory, #(#call_args),*)
                }
            }
        });
        quote!(#(#fs)*)
    });

    let init = doc.modules().map(|m| {
        let fs = m.funcs().map(|f| {
            let name = format_ident!("{}", hostcall_name(&m, &f));
            quote!(#name as _)
        });
        quote!(#(#fs),*)
    });

    quote! {
        use lucet_runtime::lucet_hostcall;
        #(#fs)*
        /// Lucet-runtime expects hostcalls to be resolved by the runtime
        /// linker (dlopen). By calling `init` in your program, we ensure that
        /// each hostcall is reachable and not garbage-collected by the
        /// compile-time linker (ld).
        pub fn init() {
            let funcs: &[*const extern "C" fn()] = &[
                #(#init),*
            ];
            ::std::mem::forget(::std::rc::Rc::new(funcs));
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Adapters for various formats for [`Uuid`]s
//!
//! [`Uuid`]: ../struct.Uuid.html

use prelude::*;

mod core_support;

/// An adaptor for formatting an [`Uuid`] as a hyphenated string.
///
/// Takes an owned instance of the [`Uuid`].
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Hyphenated(Uuid);

/// An adaptor for formatting an [`Uuid`] as a hyphenated string.
///
/// Takes a reference of the [`Uuid`].
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct HyphenatedRef<'a>(&'a Uuid);

/// An adaptor for formatting an [`Uuid`] as a simple string.
///
/// Takes an owned instance of the [`Uuid`].
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Simple(Uuid);

/// An adaptor for formatting an [`Uuid`] as a simple string.
///
/// Takes a reference of the [`Uuid`].
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct SimpleRef<'a>(&'a Uuid);

/// An adaptor for formatting an [`Uuid`] as a URN string.
///
/// Takes an owned instance of the [`Uuid`].
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Urn(Uuid);

/// An adaptor for formatting an [`Uuid`] as a URN string.
///
/// Takes a reference of the [`Uuid`].
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct UrnRef<'a>(&'a Uuid);

impl Uuid {
    /// Creates a [`UuidHyphenated`] instance from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenated`]: struct.UuidHyphenated.html
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn to_hyphenated(self) -> Hyphenated {
        Hyphenated::from_uuid(self)
    }

    /// Creates a [`UuidHyphenated`] instance from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenated`]: struct.UuidHyphenated.html
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn to_hyphenated(self) -> Hyphenated {
        Hyphenated::from_uuid(self)
    }

    /// Creates a [`UuidHyphenatedRef`] instance from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenatedRef`]: struct.UuidHyphenatedRef.html
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn to_hyphenated_ref(&self) -> HyphenatedRef {
        HyphenatedRef::from_uuid_ref(self)
    }

    /// Creates a [`UuidHyphenatedRef`] instance from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenatedRef`]: struct.UuidHyphenatedRef.html
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn to_hyphenated_ref(&self) -> HyphenatedRef {
        HyphenatedRef::from_uuid_ref(self)
    }

    /// Creates a [`UuidSimple`] instance from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimple`]: struct.UuidSimple.html
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn to_simple(self) -> Simple {
        Simple::from_uuid(self)
    }

    /// Creates a [`UuidSimple`] instance from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimple`]: struct.UuidSimple.html
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn to_simple(self) -> Simple {
        Simple::from_uuid(self)
    }

    /// Creates a [`UuidSimpleRef`] instance from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimpleRef`]: struct.UuidSimpleRef.html
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn to_simple_ref(&self) -> SimpleRef {
        SimpleRef::from_uuid_ref(self)
    }

    /// Creates a [`UuidSimpleRef`] instance from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimpleRef`]: struct.UuidSimpleRef.html
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn to_simple_ref(&self) -> SimpleRef {
        SimpleRef::from_uuid_ref(self)
    }

    /// Creates a [`UuidUrn`] instance from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrn`]: struct.UuidUrn.html
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn to_urn(self) -> Urn {
        Urn::from_uuid(self)
    }

    /// Creates a [`UuidUrn`] instance from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrn`]: struct.UuidUrn.html
    #[cfg(feature = "const_fn")]
    #[inline]
    pub constfn to_urn(self) -> Urn {
        Urn::from_uuid(self)
    }

    /// Creates a [`UuidUrnRef`] instance from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrnRef`]: struct.UuidUrnRef.html
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn to_urn_ref(&self) -> UrnRef {
        UrnRef::from_uuid_ref(self)
    }

    /// Creates a [`UuidUrnRef`] instance from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrnRef`]: struct.UuidUrnRef.html
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn to_urn_ref(&self) -> UrnRef {
        UrnRef::from_uuid_ref(self)
    }
}

impl Hyphenated {
    /// The length of a hyphenated [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub const LENGTH: usize = 36;

    /// Creates a [`UuidHyphenated`] from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenated`]: struct.UuidHyphenated.html
    #[cfg(not(feature = "const_fn"))]
    pub fn from_uuid(uuid: Uuid) -> Self {
        Hyphenated(uuid)
    }

    /// Creates a [`UuidHyphenated`] from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenated`]: struct.UuidHyphenated.html
    #[cfg(feature = "const_fn")]
    pub const fn from_uuid(uuid: Uuid) -> Self {
        Hyphenated(uuid)
    }
}

impl<'a> HyphenatedRef<'a> {
    /// The length of a hyphenated [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub const LENGTH: usize = 36;

    /// Creates a [`UuidHyphenatedRef`] from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenatedRef`]: struct.UuidHyphenatedRef.html
    #[cfg(not(feature = "const_fn"))]
    pub fn from_uuid_ref(uuid: &'a Uuid) -> Self {
        HyphenatedRef(uuid)
    }

    /// Creates a [`UuidHyphenatedRef`] from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenatedRef`]: struct.UuidHyphenatedRef.html
    #[cfg(feature = "const_fn")]
    pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self {
        HyphenatedRef(uuid)
    }
}

impl Simple {
    /// The length of a simple [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub const LENGTH: usize = 32;

    /// Creates a [`UuidSimple`] from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimple`]: struct.UuidSimple.html
    #[cfg(not(feature = "const_fn"))]
    pub fn from_uuid(uuid: Uuid) -> Self {
        Simple(uuid)
    }

    /// Creates a [`UuidSimple`] from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimple`]: struct.UuidSimple.html
    #[cfg(feature = "const_fn")]
    pub const fn from_uuid(uuid: Uuid) -> Self {
        Simple(uuid)
    }
}

impl<'a> SimpleRef<'a> {
    /// The length of a simple [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub const LENGTH: usize = 32;

    /// Creates a [`UuidSimpleRef`] from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimpleRef`]: struct.UuidSimpleRef.html
    #[cfg(not(feature = "const_fn"))]
    pub fn from_uuid_ref(uuid: &'a Uuid) -> Self {
        SimpleRef(uuid)
    }

    /// Creates a [`UuidSimpleRef`] from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimpleRef`]: struct.UuidSimpleRef.html
    #[cfg(feature = "const_fn")]
    pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self {
        SimpleRef(uuid)
    }
}

impl Urn {
    /// The length of a URN [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub const LENGTH: usize = 45;

    /// Creates a [`UuidUrn`] from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrn`]: struct.UuidUrn.html
    #[cfg(not(feature = "const_fn"))]
    pub fn from_uuid(uuid: Uuid) -> Self {
        Urn(uuid)
    }

    /// Creates a [`UuidUrn`] from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrn`]: struct.UuidUrn.html
    #[cfg(feature = "const_fn")]
    pub const fn from_uuid(uuid: Uuid) -> Self {
        Urn(uuid)
    }
}

impl<'a> UrnRef<'a> {
    /// The length of a URN [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub const LENGTH: usize = 45;

    /// Creates a [`UuidUrnRef`] from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrnRef`]: struct.UuidUrnRef.html
    #[cfg(not(feature = "const_fn"))]
    pub fn from_uuid_ref(uuid: &'a Uuid) -> Self {
        UrnRef(uuid)
    }

    /// Creates a [`UuidUrnRef`] from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrnRef`]: struct.UuidUrnRef.html
    #[cfg(feature = "const_fn")]
    pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self {
        UrnRef(&uuid)
    }
}
<commit_msg>fix syntax error<commit_after>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Adapters for various formats for [`Uuid`]s
//!
//! [`Uuid`]: ../struct.Uuid.html

use prelude::*;

mod core_support;

/// An adaptor for formatting an [`Uuid`] as a hyphenated string.
///
/// Takes an owned instance of the [`Uuid`].
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Hyphenated(Uuid);

/// An adaptor for formatting an [`Uuid`] as a hyphenated string.
///
/// Takes a reference of the [`Uuid`].
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct HyphenatedRef<'a>(&'a Uuid);

/// An adaptor for formatting an [`Uuid`] as a simple string.
///
/// Takes an owned instance of the [`Uuid`].
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Simple(Uuid);

/// An adaptor for formatting an [`Uuid`] as a simple string.
///
/// Takes a reference of the [`Uuid`].
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct SimpleRef<'a>(&'a Uuid);

/// An adaptor for formatting an [`Uuid`] as a URN string.
///
/// Takes an owned instance of the [`Uuid`].
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Urn(Uuid);

/// An adaptor for formatting an [`Uuid`] as a URN string.
///
/// Takes a reference of the [`Uuid`].
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct UrnRef<'a>(&'a Uuid);

impl Uuid {
    /// Creates a [`UuidHyphenated`] instance from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenated`]: struct.UuidHyphenated.html
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn to_hyphenated(self) -> Hyphenated {
        Hyphenated::from_uuid(self)
    }

    /// Creates a [`UuidHyphenated`] instance from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenated`]: struct.UuidHyphenated.html
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn to_hyphenated(self) -> Hyphenated {
        Hyphenated::from_uuid(self)
    }

    /// Creates a [`UuidHyphenatedRef`] instance from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenatedRef`]: struct.UuidHyphenatedRef.html
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn to_hyphenated_ref(&self) -> HyphenatedRef {
        HyphenatedRef::from_uuid_ref(self)
    }

    /// Creates a [`UuidHyphenatedRef`] instance from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenatedRef`]: struct.UuidHyphenatedRef.html
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn to_hyphenated_ref(&self) -> HyphenatedRef {
        HyphenatedRef::from_uuid_ref(self)
    }

    /// Creates a [`UuidSimple`] instance from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimple`]: struct.UuidSimple.html
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn to_simple(self) -> Simple {
        Simple::from_uuid(self)
    }

    /// Creates a [`UuidSimple`] instance from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimple`]: struct.UuidSimple.html
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn to_simple(self) -> Simple {
        Simple::from_uuid(self)
    }

    /// Creates a [`UuidSimpleRef`] instance from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimpleRef`]: struct.UuidSimpleRef.html
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn to_simple_ref(&self) -> SimpleRef {
        SimpleRef::from_uuid_ref(self)
    }

    /// Creates a [`UuidSimpleRef`] instance from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimpleRef`]: struct.UuidSimpleRef.html
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn to_simple_ref(&self) -> SimpleRef {
        SimpleRef::from_uuid_ref(self)
    }

    /// Creates a [`UuidUrn`] instance from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrn`]: struct.UuidUrn.html
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn to_urn(self) -> Urn {
        Urn::from_uuid(self)
    }

    /// Creates a [`UuidUrn`] instance from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrn`]: struct.UuidUrn.html
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn to_urn(self) -> Urn {
        Urn::from_uuid(self)
    }

    /// Creates a [`UuidUrnRef`] instance from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrnRef`]: struct.UuidUrnRef.html
    #[cfg(not(feature = "const_fn"))]
    #[inline]
    pub fn to_urn_ref(&self) -> UrnRef {
        UrnRef::from_uuid_ref(self)
    }

    /// Creates a [`UuidUrnRef`] instance from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrnRef`]: struct.UuidUrnRef.html
    #[cfg(feature = "const_fn")]
    #[inline]
    pub const fn to_urn_ref(&self) -> UrnRef {
        UrnRef::from_uuid_ref(self)
    }
}

impl Hyphenated {
    /// The length of a hyphenated [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub const LENGTH: usize = 36;

    /// Creates a [`UuidHyphenated`] from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenated`]: struct.UuidHyphenated.html
    #[cfg(not(feature = "const_fn"))]
    pub fn from_uuid(uuid: Uuid) -> Self {
        Hyphenated(uuid)
    }

    /// Creates a [`UuidHyphenated`] from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenated`]: struct.UuidHyphenated.html
    #[cfg(feature = "const_fn")]
    pub const fn from_uuid(uuid: Uuid) -> Self {
        Hyphenated(uuid)
    }
}

impl<'a> HyphenatedRef<'a> {
    /// The length of a hyphenated [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub const LENGTH: usize = 36;

    /// Creates a [`UuidHyphenatedRef`] from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenatedRef`]: struct.UuidHyphenatedRef.html
    #[cfg(not(feature = "const_fn"))]
    pub fn from_uuid_ref(uuid: &'a Uuid) -> Self {
        HyphenatedRef(uuid)
    }

    /// Creates a [`UuidHyphenatedRef`] from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidHyphenatedRef`]: struct.UuidHyphenatedRef.html
    #[cfg(feature = "const_fn")]
    pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self {
        HyphenatedRef(uuid)
    }
}

impl Simple {
    /// The length of a simple [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub const LENGTH: usize = 32;

    /// Creates a [`UuidSimple`] from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimple`]: struct.UuidSimple.html
    #[cfg(not(feature = "const_fn"))]
    pub fn from_uuid(uuid: Uuid) -> Self {
        Simple(uuid)
    }

    /// Creates a [`UuidSimple`] from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimple`]: struct.UuidSimple.html
    #[cfg(feature = "const_fn")]
    pub const fn from_uuid(uuid: Uuid) -> Self {
        Simple(uuid)
    }
}

impl<'a> SimpleRef<'a> {
    /// The length of a simple [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub const LENGTH: usize = 32;

    /// Creates a [`UuidSimpleRef`] from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimpleRef`]: struct.UuidSimpleRef.html
    #[cfg(not(feature = "const_fn"))]
    pub fn from_uuid_ref(uuid: &'a Uuid) -> Self {
        SimpleRef(uuid)
    }

    /// Creates a [`UuidSimpleRef`] from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidSimpleRef`]: struct.UuidSimpleRef.html
    #[cfg(feature = "const_fn")]
    pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self {
        SimpleRef(uuid)
    }
}

impl Urn {
    /// The length of a URN [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub const LENGTH: usize = 45;

    /// Creates a [`UuidUrn`] from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrn`]: struct.UuidUrn.html
    #[cfg(not(feature = "const_fn"))]
    pub fn from_uuid(uuid: Uuid) -> Self {
        Urn(uuid)
    }

    /// Creates a [`UuidUrn`] from a [`Uuid`].
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrn`]: struct.UuidUrn.html
    #[cfg(feature = "const_fn")]
    pub const fn from_uuid(uuid: Uuid) -> Self {
        Urn(uuid)
    }
}

impl<'a> UrnRef<'a> {
    /// The length of a URN [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub const LENGTH: usize = 45;

    /// Creates a [`UuidUrnRef`] from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrnRef`]: struct.UuidUrnRef.html
    #[cfg(not(feature = "const_fn"))]
    pub fn from_uuid_ref(uuid: &'a Uuid) -> Self {
        UrnRef(uuid)
    }

    /// Creates a [`UuidUrnRef`] from a [`Uuid`] reference.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`UuidUrnRef`]: struct.UuidUrnRef.html
    #[cfg(feature = "const_fn")]
    pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self {
        UrnRef(&uuid)
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::hash::{Hash, Hasher};
use std::net::{Ipv4Addr, SocketAddrV4};

use super::soap;
use crate::errors::{self, AddAnyPortError, AddPortError, GetExternalIpError, RemovePortError, RequestError};

use crate::common::{self, messages, parsing, parsing::RequestReponse};
use crate::PortMappingProtocol;

/// This structure represents a gateway found by the search functions.
#[derive(Clone, Debug)]
pub struct Gateway {
    /// Socket address of the gateway
    addr: SocketAddrV4,
    /// Control url of the device
    control_url: String,
}

impl Gateway {
    /// Create a new Gateway
    pub fn new(addr: SocketAddrV4, control_url: String) -> Gateway {
        Gateway {
            addr: addr,
            control_url: control_url,
        }
    }

    async fn perform_request(&self, header: &str, body: &str, ok: &str) -> Result<RequestReponse, RequestError> {
        let url = format!("{}", self);
        let text = soap::send_async(&url, soap::Action::new(header), body).await?;
        parsing::parse_response(text, ok)
    }

    /// Get the external IP address of the gateway in a tokio compatible way
    pub async fn get_external_ip(&self) -> Result<Ipv4Addr, GetExternalIpError> {
        let result = self
            .perform_request(
                messages::GET_EXTERNAL_IP_HEADER,
                &messages::format_get_external_ip_message(),
                "GetExternalIPAddressResponse",
            )
            .await;
        parsing::parse_get_external_ip_response(result)
    }

    /// Get an external socket address with our external ip and any port. This is a convenience
    /// function that calls `get_external_ip` followed by `add_any_port`
    ///
    /// The local_addr is the address where the traffic is sent to.
    /// The lease_duration parameter is in seconds. A value of 0 is infinite.
    ///
    /// # Returns
    ///
    /// The external address that was mapped on success. Otherwise an error.
    pub async fn get_any_address(
        &self,
        protocol: PortMappingProtocol,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<SocketAddrV4, AddAnyPortError> {
        let description = description.to_owned();
        let ip = self.get_external_ip().await?;
        let port = self
            .add_any_port(protocol, local_addr, lease_duration, &description)
            .await?;
        Ok(SocketAddrV4::new(ip, port))
    }

    /// Add a port mapping.with any external port.
    ///
    /// The local_addr is the address where the traffic is sent to.
    /// The lease_duration parameter is in seconds. A value of 0 is infinite.
    ///
    /// # Returns
    ///
    /// The external port that was mapped on success. Otherwise an error.
    pub async fn add_any_port(
        &self,
        protocol: PortMappingProtocol,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<u16, AddAnyPortError> {
        // This function first attempts to call AddAnyPortMapping on the IGD with a random port
        // number. If that fails due to the method being unknown it attempts to call AddPortMapping
        // instead with a random port number. If that fails due to ConflictInMappingEntry it retrys
        // with another port up to a maximum of 20 times. If it fails due to SamePortValuesRequired
        // it retrys once with the same port values.

        if local_addr.port() == 0 {
            return Err(AddAnyPortError::InternalPortZeroInvalid);
        }

        let external_port = common::random_port();

        let gateway = self.clone();
        let description = description.to_owned();

        // First, attempt to call the AddAnyPortMapping method.
        let resp = self
            .perform_request(
                messages::ADD_ANY_PORT_MAPPING_HEADER,
                &messages::format_add_any_port_mapping_message(
                    protocol,
                    external_port,
                    local_addr,
                    lease_duration,
                    &description,
                ),
                "AddAnyPortMappingResponse",
            )
            .await;
        match parsing::parse_add_any_port_mapping_response(resp) {
            Ok(port) => Ok(port),
            Err(None) => {
                // The router does not have the AddAnyPortMapping method.
                // Fall back to using AddPortMapping with a random port.
                gateway
                    .retry_add_random_port_mapping(protocol, local_addr, lease_duration, &description)
                    .await
            }
            Err(Some(err)) => Err(err),
        }
    }

    async fn retry_add_random_port_mapping(
        &self,
        protocol: PortMappingProtocol,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<u16, AddAnyPortError> {
        for _ in 0u8..20u8 {
            match self
                .add_random_port_mapping(protocol, local_addr, lease_duration, &description)
                .await
            {
                Ok(port) => return Ok(port),
                Err(AddAnyPortError::NoPortsAvailable) => continue,
                e => return e,
            }
        }
        Err(AddAnyPortError::NoPortsAvailable)
    }

    async fn add_random_port_mapping(
        &self,
        protocol: PortMappingProtocol,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<u16, AddAnyPortError> {
        let description = description.to_owned();
        let gateway = self.clone();

        let external_port = common::random_port();
        let res = self
            .add_port_mapping(protocol, external_port, local_addr, lease_duration, &description)
            .await;

        match res {
            Ok(_) => Ok(external_port),
            Err(err) => match parsing::convert_add_random_port_mapping_error(err) {
                Some(err) => Err(err),
                None => {
                    gateway
                        .add_same_port_mapping(protocol, local_addr, lease_duration, &description)
                        .await
                }
            },
        }
    }

    async fn add_same_port_mapping(
        &self,
        protocol: PortMappingProtocol,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<u16, AddAnyPortError> {
        let res = self
            .add_port_mapping(protocol, local_addr.port(), local_addr, lease_duration, description)
            .await;
        match res {
            Ok(_) => Ok(local_addr.port()),
            Err(err) => Err(parsing::convert_add_same_port_mapping_error(err)),
        }
    }

    async fn add_port_mapping(
        &self,
        protocol: PortMappingProtocol,
        external_port: u16,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<(), RequestError> {
        self.perform_request(
            messages::ADD_PORT_MAPPING_HEADER,
            &messages::format_add_port_mapping_message(
                protocol,
                external_port,
                local_addr,
                lease_duration,
                description,
            ),
            "AddPortMappingResponse",
        )
        .await?;
        Ok(())
    }

    /// Add a port mapping.
    ///
    /// The local_addr is the address where the traffic is sent to.
    /// The lease_duration parameter is in seconds. A value of 0 is infinite.
    pub async fn add_port(
        &self,
        protocol: PortMappingProtocol,
        external_port: u16,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<(), AddPortError> {
        if external_port == 0 {
            return Err(AddPortError::ExternalPortZeroInvalid);
        }
        if local_addr.port() == 0 {
            return Err(AddPortError::InternalPortZeroInvalid);
        }

        let res = self
            .add_port_mapping(protocol, external_port, local_addr, lease_duration, description)
            .await;
        if let Err(err) = res {
            return Err(parsing::convert_add_port_error(err));
        };
        Ok(())
    }

    /// Remove a port mapping.
    pub async fn remove_port(&self, protocol: PortMappingProtocol, external_port: u16) -> Result<(), RemovePortError> {
        let res = self
            .perform_request(
                messages::DELETE_PORT_MAPPING_HEADER,
                &messages::format_delete_port_message(protocol, external_port),
                "DeletePortMappingResponse",
            )
            .await;
        parsing::parse_delete_port_mapping_response(res)
    }

    /// Get one port mapping entry
    ///
    /// Gets one port mapping entry by its index.
    /// Not all existing port mappings might be visible to this client.
    /// If the index is out of bound, GetGenericPortMappingEntryError::SpecifiedArrayIndexInvalid will be returned
    pub async fn get_generic_port_mapping_entry(
        &self,
        index: u32,
    ) -> Result<parsing::PortMappingEntry, errors::GetGenericPortMappingEntryError> {
        let result = self
            .perform_request(
                messages::GET_GENERIC_PORT_MAPPING_ENTRY,
                &messages::formate_get_generic_port_mapping_entry_message(index),
                "GetGenericPortMappingEntryResponse",
            )
            .await;
        parsing::parse_get_generic_port_mapping_entry(result)
    }
}

impl fmt::Display for Gateway {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "http://{}{}", self.addr, self.control_url)
    }
}

impl PartialEq for Gateway {
    fn eq(&self, other: &Gateway) -> bool {
        self.addr == other.addr && self.control_url == other.control_url
    }
}

impl Eq for Gateway {}

impl Hash for Gateway {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.addr.hash(state);
        self.control_url.hash(state);
    }
}
<commit_msg>Make aio::Gateway struct fields public<commit_after>use std::fmt;
use std::hash::{Hash, Hasher};
use std::net::{Ipv4Addr, SocketAddrV4};

use super::soap;
use crate::errors::{self, AddAnyPortError, AddPortError, GetExternalIpError, RemovePortError, RequestError};

use crate::common::{self, messages, parsing, parsing::RequestReponse};
use crate::PortMappingProtocol;

/// This structure represents a gateway found by the search functions.
#[derive(Clone, Debug)]
pub struct Gateway {
    /// Socket address of the gateway
    pub addr: SocketAddrV4,
    /// Control url of the device
    pub control_url: String,
}

impl Gateway {
    /// Create a new Gateway
    pub fn new(addr: SocketAddrV4, control_url: String) -> Gateway {
        Gateway {
            addr: addr,
            control_url: control_url,
        }
    }

    async fn perform_request(&self, header: &str, body: &str, ok: &str) -> Result<RequestReponse, RequestError> {
        let url = format!("{}", self);
        let text = soap::send_async(&url, soap::Action::new(header), body).await?;
        parsing::parse_response(text, ok)
    }

    /// Get the external IP address of the gateway in a tokio compatible way
    pub async fn get_external_ip(&self) -> Result<Ipv4Addr, GetExternalIpError> {
        let result = self
            .perform_request(
                messages::GET_EXTERNAL_IP_HEADER,
                &messages::format_get_external_ip_message(),
                "GetExternalIPAddressResponse",
            )
            .await;
        parsing::parse_get_external_ip_response(result)
    }

    /// Get an external socket address with our external ip and any port. This is a convenience
    /// function that calls `get_external_ip` followed by `add_any_port`
    ///
    /// The local_addr is the address where the traffic is sent to.
    /// The lease_duration parameter is in seconds. A value of 0 is infinite.
    ///
    /// # Returns
    ///
    /// The external address that was mapped on success. Otherwise an error.
    pub async fn get_any_address(
        &self,
        protocol: PortMappingProtocol,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<SocketAddrV4, AddAnyPortError> {
        let description = description.to_owned();
        let ip = self.get_external_ip().await?;
        let port = self
            .add_any_port(protocol, local_addr, lease_duration, &description)
            .await?;
        Ok(SocketAddrV4::new(ip, port))
    }

    /// Add a port mapping.with any external port.
    ///
    /// The local_addr is the address where the traffic is sent to.
    /// The lease_duration parameter is in seconds. A value of 0 is infinite.
    ///
    /// # Returns
    ///
    /// The external port that was mapped on success. Otherwise an error.
    pub async fn add_any_port(
        &self,
        protocol: PortMappingProtocol,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<u16, AddAnyPortError> {
        // This function first attempts to call AddAnyPortMapping on the IGD with a random port
        // number. If that fails due to the method being unknown it attempts to call AddPortMapping
        // instead with a random port number. If that fails due to ConflictInMappingEntry it retrys
        // with another port up to a maximum of 20 times. If it fails due to SamePortValuesRequired
        // it retrys once with the same port values.

        if local_addr.port() == 0 {
            return Err(AddAnyPortError::InternalPortZeroInvalid);
        }

        let external_port = common::random_port();

        let gateway = self.clone();
        let description = description.to_owned();

        // First, attempt to call the AddAnyPortMapping method.
        let resp = self
            .perform_request(
                messages::ADD_ANY_PORT_MAPPING_HEADER,
                &messages::format_add_any_port_mapping_message(
                    protocol,
                    external_port,
                    local_addr,
                    lease_duration,
                    &description,
                ),
                "AddAnyPortMappingResponse",
            )
            .await;
        match parsing::parse_add_any_port_mapping_response(resp) {
            Ok(port) => Ok(port),
            Err(None) => {
                // The router does not have the AddAnyPortMapping method.
                // Fall back to using AddPortMapping with a random port.
                gateway
                    .retry_add_random_port_mapping(protocol, local_addr, lease_duration, &description)
                    .await
            }
            Err(Some(err)) => Err(err),
        }
    }

    async fn retry_add_random_port_mapping(
        &self,
        protocol: PortMappingProtocol,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<u16, AddAnyPortError> {
        for _ in 0u8..20u8 {
            match self
                .add_random_port_mapping(protocol, local_addr, lease_duration, &description)
                .await
            {
                Ok(port) => return Ok(port),
                Err(AddAnyPortError::NoPortsAvailable) => continue,
                e => return e,
            }
        }
        Err(AddAnyPortError::NoPortsAvailable)
    }

    async fn add_random_port_mapping(
        &self,
        protocol: PortMappingProtocol,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<u16, AddAnyPortError> {
        let description = description.to_owned();
        let gateway = self.clone();

        let external_port = common::random_port();
        let res = self
            .add_port_mapping(protocol, external_port, local_addr, lease_duration, &description)
            .await;

        match res {
            Ok(_) => Ok(external_port),
            Err(err) => match parsing::convert_add_random_port_mapping_error(err) {
                Some(err) => Err(err),
                None => {
                    gateway
                        .add_same_port_mapping(protocol, local_addr, lease_duration, &description)
                        .await
                }
            },
        }
    }

    async fn add_same_port_mapping(
        &self,
        protocol: PortMappingProtocol,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<u16, AddAnyPortError> {
        let res = self
            .add_port_mapping(protocol, local_addr.port(), local_addr, lease_duration, description)
            .await;
        match res {
            Ok(_) => Ok(local_addr.port()),
            Err(err) => Err(parsing::convert_add_same_port_mapping_error(err)),
        }
    }

    async fn add_port_mapping(
        &self,
        protocol: PortMappingProtocol,
        external_port: u16,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<(), RequestError> {
        self.perform_request(
            messages::ADD_PORT_MAPPING_HEADER,
            &messages::format_add_port_mapping_message(
                protocol,
                external_port,
                local_addr,
                lease_duration,
                description,
            ),
            "AddPortMappingResponse",
        )
        .await?;
        Ok(())
    }

    /// Add a port mapping.
    ///
    /// The local_addr is the address where the traffic is sent to.
    /// The lease_duration parameter is in seconds. A value of 0 is infinite.
    pub async fn add_port(
        &self,
        protocol: PortMappingProtocol,
        external_port: u16,
        local_addr: SocketAddrV4,
        lease_duration: u32,
        description: &str,
    ) -> Result<(), AddPortError> {
        if external_port == 0 {
            return Err(AddPortError::ExternalPortZeroInvalid);
        }
        if local_addr.port() == 0 {
            return Err(AddPortError::InternalPortZeroInvalid);
        }

        let res = self
            .add_port_mapping(protocol, external_port, local_addr, lease_duration, description)
            .await;
        if let Err(err) = res {
            return Err(parsing::convert_add_port_error(err));
        };
        Ok(())
    }

    /// Remove a port mapping.
    pub async fn remove_port(&self, protocol: PortMappingProtocol, external_port: u16) -> Result<(), RemovePortError> {
        let res = self
            .perform_request(
                messages::DELETE_PORT_MAPPING_HEADER,
                &messages::format_delete_port_message(protocol, external_port),
                "DeletePortMappingResponse",
            )
            .await;
        parsing::parse_delete_port_mapping_response(res)
    }

    /// Get one port mapping entry
    ///
    /// Gets one port mapping entry by its index.
    /// Not all existing port mappings might be visible to this client.
    /// If the index is out of bound, GetGenericPortMappingEntryError::SpecifiedArrayIndexInvalid will be returned
    pub async fn get_generic_port_mapping_entry(
        &self,
        index: u32,
    ) -> Result<parsing::PortMappingEntry, errors::GetGenericPortMappingEntryError> {
        let result = self
            .perform_request(
                messages::GET_GENERIC_PORT_MAPPING_ENTRY,
                &messages::formate_get_generic_port_mapping_entry_message(index),
                "GetGenericPortMappingEntryResponse",
            )
            .await;
        parsing::parse_get_generic_port_mapping_entry(result)
    }
}

impl fmt::Display for Gateway {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "http://{}{}", self.addr, self.control_url)
    }
}

impl PartialEq for Gateway {
    fn eq(&self, other: &Gateway) -> bool {
        self.addr == other.addr && self.control_url == other.control_url
    }
}

impl Eq for Gateway {}

impl Hash for Gateway {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.addr.hash(state);
        self.control_url.hash(state);
    }
}
<|endoftext|>