<commit_before>//! Traits for working with JavaScript objects.

#[cfg(feature = "legacy-runtime")]
pub(crate) mod class;

#[cfg(feature = "legacy-runtime")]
pub use self::class::{Class, ClassDescriptor};
pub use self::traits::*;

#[cfg(feature = "legacy-runtime")]
mod traits {
    use crate::context::Context;
    use crate::handle::{Handle, Managed};
    use crate::result::{JsResult, NeonResult, Throw};
    use crate::types::utf8::Utf8;
    use crate::types::{build, JsArray, JsValue, Value};
    use neon_runtime::raw;

    /// A property key in a JavaScript object.
    pub trait PropertyKey {
        unsafe fn get_from(self, out: &mut raw::Local, obj: raw::Local) -> bool;
        unsafe fn set_from(self, out: &mut bool, obj: raw::Local, val: raw::Local) -> bool;
    }

    impl PropertyKey for u32 {
        unsafe fn get_from(self, out: &mut raw::Local, obj: raw::Local) -> bool {
            neon_runtime::object::get_index(out, obj, self)
        }

        unsafe fn set_from(self, out: &mut bool, obj: raw::Local, val: raw::Local) -> bool {
            neon_runtime::object::set_index(out, obj, self, val)
        }
    }

    impl<'a, K: Value> PropertyKey for Handle<'a, K> {
        unsafe fn get_from(self, out: &mut raw::Local, obj: raw::Local) -> bool {
            neon_runtime::object::get(out, obj, self.to_raw())
        }

        unsafe fn set_from(self, out: &mut bool, obj: raw::Local, val: raw::Local) -> bool {
            neon_runtime::object::set(out, obj, self.to_raw(), val)
        }
    }

    impl<'a> PropertyKey for &'a str {
        unsafe fn get_from(self, out: &mut raw::Local, obj: raw::Local) -> bool {
            let (ptr, len) = Utf8::from(self).into_small_unwrap().lower();
            neon_runtime::object::get_string(out, obj, ptr, len)
        }

        unsafe fn set_from(self, out: &mut bool, obj: raw::Local, val: raw::Local) -> bool {
            let (ptr, len) = Utf8::from(self).into_small_unwrap().lower();
            neon_runtime::object::set_string(out, obj, ptr, len, val)
        }
    }

    /// The trait of all object types.
    pub trait Object: Value {
        fn get<'a, C: Context<'a>, K: PropertyKey>(
            self,
            cx: &mut C,
            key: K,
        ) -> NeonResult<Handle<'a, JsValue>> {
            build(cx.env(), |out| unsafe { key.get_from(out, self.to_raw()) })
        }

        fn get_own_property_names<'a, C: Context<'a>>(self, cx: &mut C) -> JsResult<'a, JsArray> {
            let env = cx.env();
            build(env, |out| unsafe {
                neon_runtime::object::get_own_property_names(out, env.to_raw(), self.to_raw())
            })
        }

        fn set<'a, C: Context<'a>, K: PropertyKey, W: Value>(
            self,
            _: &mut C,
            key: K,
            val: Handle<W>,
        ) -> NeonResult<bool> {
            let mut result = false;
            if unsafe { key.set_from(&mut result, self.to_raw(), val.to_raw()) } {
                Ok(result)
            } else {
                Err(Throw)
            }
        }
    }

    /// The trait of types that can be a function's `this` binding.
    pub unsafe trait This: Managed {
        #[allow(clippy::wrong_self_convention)]
        fn as_this(h: raw::Local) -> Self;
    }
}

#[cfg(feature = "napi-1")]
mod traits {
    use crate::context::internal::Env;
    use crate::context::Context;
    use crate::handle::{Handle, Managed, Root};
    use crate::result::{NeonResult, Throw};
    use crate::types::utf8::Utf8;
    use crate::types::{build, JsValue, Value};
    use neon_runtime::raw;

    #[cfg(feature = "napi-6")]
    use crate::result::JsResult;
    #[cfg(feature = "napi-6")]
    use crate::types::JsArray;

    /// A property key in a JavaScript object.
    pub trait PropertyKey {
        unsafe fn get_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut raw::Local,
            obj: raw::Local,
        ) -> bool;

        unsafe fn set_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut bool,
            obj: raw::Local,
            val: raw::Local,
        ) -> bool;
    }

    impl PropertyKey for u32 {
        unsafe fn get_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut raw::Local,
            obj: raw::Local,
        ) -> bool {
            neon_runtime::object::get_index(out, cx.env().to_raw(), obj, self)
        }

        unsafe fn set_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut bool,
            obj: raw::Local,
            val: raw::Local,
        ) -> bool {
            neon_runtime::object::set_index(out, cx.env().to_raw(), obj, self, val)
        }
    }

    impl<'a, K: Value> PropertyKey for Handle<'a, K> {
        unsafe fn get_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut raw::Local,
            obj: raw::Local,
        ) -> bool {
            let env = cx.env().to_raw();

            neon_runtime::object::get(out, env, obj, self.to_raw())
        }

        unsafe fn set_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut bool,
            obj: raw::Local,
            val: raw::Local,
        ) -> bool {
            let env = cx.env().to_raw();

            neon_runtime::object::set(out, env, obj, self.to_raw(), val)
        }
    }

    impl<'a> PropertyKey for &'a str {
        unsafe fn get_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut raw::Local,
            obj: raw::Local,
        ) -> bool {
            let (ptr, len) = Utf8::from(self).into_small_unwrap().lower();
            let env = cx.env().to_raw();

            neon_runtime::object::get_string(env, out, obj, ptr, len)
        }

        unsafe fn set_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut bool,
            obj: raw::Local,
            val: raw::Local,
        ) -> bool {
            let (ptr, len) = Utf8::from(self).into_small_unwrap().lower();
            let env = cx.env().to_raw();

            neon_runtime::object::set_string(env, out, obj, ptr, len, val)
        }
    }

    /// The trait of all object types.
    pub trait Object: Value {
        fn get<'a, C: Context<'a>, K: PropertyKey>(
            self,
            cx: &mut C,
            key: K,
        ) -> NeonResult<Handle<'a, JsValue>> {
            build(cx.env(), |out| unsafe {
                key.get_from(cx, out, self.to_raw())
            })
        }

        #[cfg(feature = "napi-6")]
        fn get_own_property_names<'a, C: Context<'a>>(self, cx: &mut C) -> JsResult<'a, JsArray> {
            let env = cx.env();

            build(cx.env(), |out| unsafe {
                neon_runtime::object::get_own_property_names(out, env.to_raw(), self.to_raw())
            })
        }

        fn set<'a, C: Context<'a>, K: PropertyKey, W: Value>(
            self,
            cx: &mut C,
            key: K,
            val: Handle<W>,
        ) -> NeonResult<bool> {
            let mut result = false;
            if unsafe { key.set_from(cx, &mut result, self.to_raw(), val.to_raw()) } {
                Ok(result)
            } else {
                Err(Throw)
            }
        }

        fn root<'a, C: Context<'a>>(&self, cx: &mut C) -> Root<Self> {
            Root::new(cx, self)
        }
    }

    /// The trait of types that can be a function's `this` binding.
    pub unsafe trait This: Managed {
        #[allow(clippy::wrong_self_convention)]
        fn as_this(env: Env, h: raw::Local) -> Self;
    }
}
<commit_msg>API docs for `neon::object` module top-level.<commit_after>//! Traits for working with JavaScript objects.
//!
//! This module defines the [`Object`](Object) trait, which is implemented
//! by all object types in the [JavaScript type hierarchy][hierarchy]. This
//! trait provides key operations in the semantics of JavaScript objects,
//! such as getting and setting an object's properties.
//!
//! ## Property Keys
//!
//! Object properties are accessed by a _property key_, which in JavaScript
//! can be a string or [symbol][symbol]. (Neon does not yet have support for
//! symbols.) For convenience, the [`PropertyKey`](PropertyKey) trait allows
//! Neon programs to use various Rust string types, as well as numeric types,
//! as keys when accessing object properties, converting the keys to strings
//! as necessary:
//!
//! ```
//! # use neon::prelude::*;
//! fn set_and_check<'a>(
//!     cx: &mut impl Context<'a>,
//!     obj: Handle<'a, JsObject>
//! ) -> JsResult<'a, JsValue> {
//!     let value = cx.string("hello!");
//!     // set property "17" with integer shorthand
//!     obj.set(17, value)?;
//!     // get property "17" with string shorthand
//!     // returns the same value ("hello!")
//!     obj.get("17")
//! }
//! ```
//!
//! [hierarchy]: crate::types#the-javascript-type-hierarchy
//! [symbol]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

#[cfg(feature = "legacy-runtime")]
pub(crate) mod class;

#[cfg(feature = "legacy-runtime")]
pub use self::class::{Class, ClassDescriptor};
pub use self::traits::*;

#[cfg(feature = "legacy-runtime")]
mod traits {
    use crate::context::Context;
    use crate::handle::{Handle, Managed};
    use crate::result::{JsResult, NeonResult, Throw};
    use crate::types::utf8::Utf8;
    use crate::types::{build, JsArray, JsValue, Value};
    use neon_runtime::raw;

    /// A property key in a JavaScript object.
    pub trait PropertyKey {
        unsafe fn get_from(self, out: &mut raw::Local, obj: raw::Local) -> bool;
        unsafe fn set_from(self, out: &mut bool, obj: raw::Local, val: raw::Local) -> bool;
    }

    impl PropertyKey for u32 {
        unsafe fn get_from(self, out: &mut raw::Local, obj: raw::Local) -> bool {
            neon_runtime::object::get_index(out, obj, self)
        }

        unsafe fn set_from(self, out: &mut bool, obj: raw::Local, val: raw::Local) -> bool {
            neon_runtime::object::set_index(out, obj, self, val)
        }
    }

    impl<'a, K: Value> PropertyKey for Handle<'a, K> {
        unsafe fn get_from(self, out: &mut raw::Local, obj: raw::Local) -> bool {
            neon_runtime::object::get(out, obj, self.to_raw())
        }

        unsafe fn set_from(self, out: &mut bool, obj: raw::Local, val: raw::Local) -> bool {
            neon_runtime::object::set(out, obj, self.to_raw(), val)
        }
    }

    impl<'a> PropertyKey for &'a str {
        unsafe fn get_from(self, out: &mut raw::Local, obj: raw::Local) -> bool {
            let (ptr, len) = Utf8::from(self).into_small_unwrap().lower();
            neon_runtime::object::get_string(out, obj, ptr, len)
        }

        unsafe fn set_from(self, out: &mut bool, obj: raw::Local, val: raw::Local) -> bool {
            let (ptr, len) = Utf8::from(self).into_small_unwrap().lower();
            neon_runtime::object::set_string(out, obj, ptr, len, val)
        }
    }

    /// The trait of all object types.
    pub trait Object: Value {
        fn get<'a, C: Context<'a>, K: PropertyKey>(
            self,
            cx: &mut C,
            key: K,
        ) -> NeonResult<Handle<'a, JsValue>> {
            build(cx.env(), |out| unsafe { key.get_from(out, self.to_raw()) })
        }

        fn get_own_property_names<'a, C: Context<'a>>(self, cx: &mut C) -> JsResult<'a, JsArray> {
            let env = cx.env();
            build(env, |out| unsafe {
                neon_runtime::object::get_own_property_names(out, env.to_raw(), self.to_raw())
            })
        }

        fn set<'a, C: Context<'a>, K: PropertyKey, W: Value>(
            self,
            _: &mut C,
            key: K,
            val: Handle<W>,
        ) -> NeonResult<bool> {
            let mut result = false;
            if unsafe { key.set_from(&mut result, self.to_raw(), val.to_raw()) } {
                Ok(result)
            } else {
                Err(Throw)
            }
        }
    }

    /// The trait of types that can be a function's `this` binding.
    pub unsafe trait This: Managed {
        #[allow(clippy::wrong_self_convention)]
        fn as_this(h: raw::Local) -> Self;
    }
}

#[cfg(feature = "napi-1")]
mod traits {
    use crate::context::internal::Env;
    use crate::context::Context;
    use crate::handle::{Handle, Managed, Root};
    use crate::result::{NeonResult, Throw};
    use crate::types::utf8::Utf8;
    use crate::types::{build, JsValue, Value};
    use neon_runtime::raw;

    #[cfg(feature = "napi-6")]
    use crate::result::JsResult;
    #[cfg(feature = "napi-6")]
    use crate::types::JsArray;

    /// A property key in a JavaScript object.
    pub trait PropertyKey {
        unsafe fn get_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut raw::Local,
            obj: raw::Local,
        ) -> bool;

        unsafe fn set_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut bool,
            obj: raw::Local,
            val: raw::Local,
        ) -> bool;
    }

    impl PropertyKey for u32 {
        unsafe fn get_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut raw::Local,
            obj: raw::Local,
        ) -> bool {
            neon_runtime::object::get_index(out, cx.env().to_raw(), obj, self)
        }

        unsafe fn set_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut bool,
            obj: raw::Local,
            val: raw::Local,
        ) -> bool {
            neon_runtime::object::set_index(out, cx.env().to_raw(), obj, self, val)
        }
    }

    impl<'a, K: Value> PropertyKey for Handle<'a, K> {
        unsafe fn get_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut raw::Local,
            obj: raw::Local,
        ) -> bool {
            let env = cx.env().to_raw();

            neon_runtime::object::get(out, env, obj, self.to_raw())
        }

        unsafe fn set_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut bool,
            obj: raw::Local,
            val: raw::Local,
        ) -> bool {
            let env = cx.env().to_raw();

            neon_runtime::object::set(out, env, obj, self.to_raw(), val)
        }
    }

    impl<'a> PropertyKey for &'a str {
        unsafe fn get_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut raw::Local,
            obj: raw::Local,
        ) -> bool {
            let (ptr, len) = Utf8::from(self).into_small_unwrap().lower();
            let env = cx.env().to_raw();

            neon_runtime::object::get_string(env, out, obj, ptr, len)
        }

        unsafe fn set_from<'c, C: Context<'c>>(
            self,
            cx: &mut C,
            out: &mut bool,
            obj: raw::Local,
            val: raw::Local,
        ) -> bool {
            let (ptr, len) = Utf8::from(self).into_small_unwrap().lower();
            let env = cx.env().to_raw();

            neon_runtime::object::set_string(env, out, obj, ptr, len, val)
        }
    }

    /// The trait of all object types.
    pub trait Object: Value {
        fn get<'a, C: Context<'a>, K: PropertyKey>(
            self,
            cx: &mut C,
            key: K,
        ) -> NeonResult<Handle<'a, JsValue>> {
            build(cx.env(), |out| unsafe {
                key.get_from(cx, out, self.to_raw())
            })
        }

        #[cfg(feature = "napi-6")]
        fn get_own_property_names<'a, C: Context<'a>>(self, cx: &mut C) -> JsResult<'a, JsArray> {
            let env = cx.env();

            build(cx.env(), |out| unsafe {
                neon_runtime::object::get_own_property_names(out, env.to_raw(), self.to_raw())
            })
        }

        fn set<'a, C: Context<'a>, K: PropertyKey, W: Value>(
            self,
            cx: &mut C,
            key: K,
            val: Handle<W>,
        ) -> NeonResult<bool> {
            let mut result = false;
            if unsafe { key.set_from(cx, &mut result, self.to_raw(), val.to_raw()) } {
                Ok(result)
            } else {
                Err(Throw)
            }
        }

        fn root<'a, C: Context<'a>>(&self, cx: &mut C) -> Root<Self> {
            Root::new(cx, self)
        }
    }

    /// The trait of types that can be a function's `this` binding.
    pub unsafe trait This: Managed {
        #[allow(clippy::wrong_self_convention)]
        fn as_this(env: Env, h: raw::Local) -> Self;
    }
}
<|endoftext|>


<commit_before>//! Handle process life-time and message passing for proc-macro client

use std::{
    convert::{TryFrom, TryInto},
    ffi::{OsStr, OsString},
    io::{self, BufRead, BufReader, Write},
    path::{Path, PathBuf},
    process::{Child, Command, Stdio},
    sync::{Arc, Weak},
};

use crossbeam_channel::{bounded, Receiver, Sender};
use tt::Subtree;

use crate::{
    msg::{ErrorCode, Message, Request, Response, ResponseError},
    rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind},
};

#[derive(Debug, Default)]
pub(crate) struct ProcMacroProcessSrv {
    inner: Weak<Sender<Task>>,
}

#[derive(Debug)]
pub(crate) struct ProcMacroProcessThread {
    // XXX: drop order is significant
    sender: Arc<Sender<Task>>,
    handle: jod_thread::JoinHandle<()>,
}

impl ProcMacroProcessSrv {
    pub(crate) fn run(
        process_path: PathBuf,
        args: impl IntoIterator<Item = impl AsRef<OsStr>>,
    ) -> io::Result<(ProcMacroProcessThread, ProcMacroProcessSrv)> {
        let process = Process::run(process_path, args)?;

        let (task_tx, task_rx) = bounded(0);
        let handle = jod_thread::spawn(move || {
            client_loop(task_rx, process);
        });

        let task_tx = Arc::new(task_tx);
        let srv = ProcMacroProcessSrv { inner: Arc::downgrade(&task_tx) };
        let thread = ProcMacroProcessThread { handle, sender: task_tx };

        Ok((thread, srv))
    }

    pub(crate) fn find_proc_macros(
        &self,
        dylib_path: &Path,
    ) -> Result<Vec<(String, ProcMacroKind)>, tt::ExpansionError> {
        let task = ListMacrosTask { lib: dylib_path.to_path_buf() };

        let result: ListMacrosResult = self.send_task(Request::ListMacro(task))?;
        Ok(result.macros)
    }

    pub(crate) fn custom_derive(
        &self,
        dylib_path: &Path,
        subtree: &Subtree,
        derive_name: &str,
    ) -> Result<Subtree, tt::ExpansionError> {
        let task = ExpansionTask {
            macro_body: subtree.clone(),
            macro_name: derive_name.to_string(),
            attributes: None,
            lib: dylib_path.to_path_buf(),
        };

        let result: ExpansionResult = self.send_task(Request::ExpansionMacro(task))?;
        Ok(result.expansion)
    }

    pub(crate) fn send_task<R>(&self, req: Request) -> Result<R, tt::ExpansionError>
    where
        R: TryFrom<Response, Error = &'static str>,
    {
        let (result_tx, result_rx) = bounded(0);
        let sender = match self.inner.upgrade() {
            None => {
                return Err(tt::ExpansionError::Unknown("Proc macro process is closed.".into()))
            }
            Some(it) => it,
        };
        sender.send(Task { req, result_tx }).unwrap();
        let res = result_rx
            .recv()
            .map_err(|_| tt::ExpansionError::Unknown("Proc macro thread is closed.".into()))?;

        match res {
            Some(Response::Error(err)) => {
                return Err(tt::ExpansionError::ExpansionError(err.message));
            }
            Some(res) => Ok(res.try_into().map_err(|err| {
                tt::ExpansionError::Unknown(format!("Fail to get response, reason : {:#?} ", err))
            })?),
            None => Err(tt::ExpansionError::Unknown("Empty result".into())),
        }
    }
}

fn client_loop(task_rx: Receiver<Task>, mut process: Process) {
    let (mut stdin, mut stdout) = match process.stdio() {
        None => return,
        Some(it) => it,
    };

    for Task { req, result_tx } in task_rx {
        match send_request(&mut stdin, &mut stdout, req) {
            Ok(res) => result_tx.send(res).unwrap(),
            Err(_err) => {
                let res = Response::Error(ResponseError {
                    code: ErrorCode::ServerErrorEnd,
                    message: "Server closed".into(),
                });
                result_tx.send(res.into()).unwrap();
                // Restart the process
                if process.restart().is_err() {
                    break;
                }
                let stdio = match process.stdio() {
                    None => break,
                    Some(it) => it,
                };
                stdin = stdio.0;
                stdout = stdio.1;
            }
        }
    }
}

struct Task {
    req: Request,
    result_tx: Sender<Option<Response>>,
}

struct Process {
    path: PathBuf,
    args: Vec<OsString>,
    child: Child,
}

impl Drop for Process {
    fn drop(&mut self) {
        let _ = self.child.kill();
    }
}

impl Process {
    fn run(
        path: PathBuf,
        args: impl IntoIterator<Item = impl AsRef<OsStr>>,
    ) -> io::Result<Process> {
        let args = args.into_iter().map(|s| s.as_ref().into()).collect();
        let child = mk_child(&path, &args)?;
        Ok(Process { path, args, child })
    }

    fn restart(&mut self) -> io::Result<()> {
        let _ = self.child.kill();
        self.child = mk_child(&self.path, &self.args)?;
        Ok(())
    }

    fn stdio(&mut self) -> Option<(impl Write, impl BufRead)> {
        let stdin = self.child.stdin.take()?;
        let stdout = self.child.stdout.take()?;
        let read = BufReader::new(stdout);

        Some((stdin, read))
    }
}

fn mk_child(path: &Path, args: impl IntoIterator<Item = impl AsRef<OsStr>>) -> io::Result<Child> {
    Command::new(&path)
        .args(args)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::inherit())
        .spawn()
}

fn send_request(
    mut writer: &mut impl Write,
    mut reader: &mut impl BufRead,
    req: Request,
) -> io::Result<Option<Response>> {
    req.write(&mut writer)?;
    Ok(Response::read(&mut reader)?)
}
<commit_msg>Unwrap `process.stdio()` result<commit_after>//! Handle process life-time and message passing for proc-macro client

use std::{
    convert::{TryFrom, TryInto},
    ffi::{OsStr, OsString},
    io::{self, BufRead, BufReader, Write},
    path::{Path, PathBuf},
    process::{Child, Command, Stdio},
    sync::{Arc, Weak},
};

use crossbeam_channel::{bounded, Receiver, Sender};
use tt::Subtree;

use crate::{
    msg::{ErrorCode, Message, Request, Response, ResponseError},
    rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind},
};

#[derive(Debug, Default)]
pub(crate) struct ProcMacroProcessSrv {
    inner: Weak<Sender<Task>>,
}

#[derive(Debug)]
pub(crate) struct ProcMacroProcessThread {
    // XXX: drop order is significant
    sender: Arc<Sender<Task>>,
    handle: jod_thread::JoinHandle<()>,
}

impl ProcMacroProcessSrv {
    pub(crate) fn run(
        process_path: PathBuf,
        args: impl IntoIterator<Item = impl AsRef<OsStr>>,
    ) -> io::Result<(ProcMacroProcessThread, ProcMacroProcessSrv)> {
        let process = Process::run(process_path, args)?;

        let (task_tx, task_rx) = bounded(0);
        let handle = jod_thread::spawn(move || {
            client_loop(task_rx, process);
        });

        let task_tx = Arc::new(task_tx);
        let srv = ProcMacroProcessSrv { inner: Arc::downgrade(&task_tx) };
        let thread = ProcMacroProcessThread { handle, sender: task_tx };

        Ok((thread, srv))
    }

    pub(crate) fn find_proc_macros(
        &self,
        dylib_path: &Path,
    ) -> Result<Vec<(String, ProcMacroKind)>, tt::ExpansionError> {
        let task = ListMacrosTask { lib: dylib_path.to_path_buf() };

        let result: ListMacrosResult = self.send_task(Request::ListMacro(task))?;
        Ok(result.macros)
    }

    pub(crate) fn custom_derive(
        &self,
        dylib_path: &Path,
        subtree: &Subtree,
        derive_name: &str,
    ) -> Result<Subtree, tt::ExpansionError> {
        let task = ExpansionTask {
            macro_body: subtree.clone(),
            macro_name: derive_name.to_string(),
            attributes: None,
            lib: dylib_path.to_path_buf(),
        };

        let result: ExpansionResult = self.send_task(Request::ExpansionMacro(task))?;
        Ok(result.expansion)
    }

    pub(crate) fn send_task<R>(&self, req: Request) -> Result<R, tt::ExpansionError>
    where
        R: TryFrom<Response, Error = &'static str>,
    {
        let (result_tx, result_rx) = bounded(0);
        let sender = match self.inner.upgrade() {
            None => {
                return Err(tt::ExpansionError::Unknown("Proc macro process is closed.".into()))
            }
            Some(it) => it,
        };
        sender.send(Task { req, result_tx }).unwrap();
        let res = result_rx
            .recv()
            .map_err(|_| tt::ExpansionError::Unknown("Proc macro thread is closed.".into()))?;

        match res {
            Some(Response::Error(err)) => {
                return Err(tt::ExpansionError::ExpansionError(err.message));
            }
            Some(res) => Ok(res.try_into().map_err(|err| {
                tt::ExpansionError::Unknown(format!("Fail to get response, reason : {:#?} ", err))
            })?),
            None => Err(tt::ExpansionError::Unknown("Empty result".into())),
        }
    }
}

fn client_loop(task_rx: Receiver<Task>, mut process: Process) {
    let (mut stdin, mut stdout) = process.stdio().expect("couldn't access child stdio");

    for Task { req, result_tx } in task_rx {
        match send_request(&mut stdin, &mut stdout, req) {
            Ok(res) => result_tx.send(res).unwrap(),
            Err(_err) => {
                let res = Response::Error(ResponseError {
                    code: ErrorCode::ServerErrorEnd,
                    message: "Server closed".into(),
                });
                result_tx.send(res.into()).unwrap();
                // Restart the process
                if process.restart().is_err() {
                    break;
                }
                let stdio = match process.stdio() {
                    None => break,
                    Some(it) => it,
                };
                stdin = stdio.0;
                stdout = stdio.1;
            }
        }
    }
}

struct Task {
    req: Request,
    result_tx: Sender<Option<Response>>,
}

struct Process {
    path: PathBuf,
    args: Vec<OsString>,
    child: Child,
}

impl Drop for Process {
    fn drop(&mut self) {
        let _ = self.child.kill();
    }
}

impl Process {
    fn run(
        path: PathBuf,
        args: impl IntoIterator<Item = impl AsRef<OsStr>>,
    ) -> io::Result<Process> {
        let args = args.into_iter().map(|s| s.as_ref().into()).collect();
        let child = mk_child(&path, &args)?;
        Ok(Process { path, args, child })
    }

    fn restart(&mut self) -> io::Result<()> {
        let _ = self.child.kill();
        self.child = mk_child(&self.path, &self.args)?;
        Ok(())
    }

    fn stdio(&mut self) -> Option<(impl Write, impl BufRead)> {
        let stdin = self.child.stdin.take()?;
        let stdout = self.child.stdout.take()?;
        let read = BufReader::new(stdout);

        Some((stdin, read))
    }
}

fn mk_child(path: &Path, args: impl IntoIterator<Item = impl AsRef<OsStr>>) -> io::Result<Child> {
    Command::new(&path)
        .args(args)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::inherit())
        .spawn()
}

fn send_request(
    mut writer: &mut impl Write,
    mut reader: &mut impl BufRead,
    req: Request,
) -> io::Result<Option<Response>> {
    req.write(&mut writer)?;
    Ok(Response::read(&mut reader)?)
}
<|endoftext|>


<commit_before>use std::cell::RefCell;

use itertools::Itertools;
use hir::{source_binder, diagnostics::{Diagnostic as _, DiagnosticSink}};
use ra_db::SourceDatabase;
use ra_syntax::{
    T, Location, TextRange, SyntaxNode,
    ast::{self, AstNode, NamedFieldList, NamedField},
};
use ra_assists::ast_editor::{AstEditor, AstBuilder};
use ra_text_edit::{TextEdit, TextEditBuilder};
use ra_prof::profile;

use crate::{Diagnostic, FileId, FileSystemEdit, SourceChange, SourceFileEdit, db::RootDatabase};

#[derive(Debug, Copy, Clone)]
pub enum Severity {
    Error,
    WeakWarning,
}

pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> {
    let _p = profile("diagnostics");
    let parse = db.parse(file_id);
    let mut res = Vec::new();

    res.extend(parse.errors.iter().map(|err| Diagnostic {
        range: location_to_range(err.location()),
        message: format!("Syntax Error: {}", err),
        severity: Severity::Error,
        fix: None,
    }));

    let source_file = parse.tree;

    for node in source_file.syntax().descendants() {
        check_unnecessary_braces_in_use_statement(&mut res, file_id, node);
        check_struct_shorthand_initialization(&mut res, file_id, node);
    }
    let res = RefCell::new(res);
    let mut sink = DiagnosticSink::new(|d| {
        res.borrow_mut().push(Diagnostic {
            message: d.message(),
            range: d.highlight_range(),
            severity: Severity::Error,
            fix: None,
        })
    })
    .on::<hir::diagnostics::UnresolvedModule, _>(|d| {
        let source_root = db.file_source_root(d.file().original_file(db));
        let create_file = FileSystemEdit::CreateFile { source_root, path: d.candidate.clone() };
        let fix = SourceChange::file_system_edit("create module", create_file);
        res.borrow_mut().push(Diagnostic {
            range: d.highlight_range(),
            message: d.message(),
            severity: Severity::Error,
            fix: Some(fix),
        })
    })
    .on::<hir::diagnostics::MissingFields, _>(|d| {
        //TODO: commment
        let file_id = d.file().original_file(db);
        let source_file = db.parse(file_id).tree;
        let syntax_node = d.syntax_node_ptr();
        let node = NamedFieldList::cast(syntax_node.to_node(source_file.syntax())).unwrap();
        let mut ast_editor = AstEditor::new(node);
        for f in d.missed_fields.iter() {
            ast_editor.append_field(&AstBuilder::<NamedField>::from_name(f));
        }

        let mut builder = TextEditBuilder::default();
        ast_editor.into_text_edit(&mut builder);
        let fix =
            SourceChange::source_file_edit_from("fill struct fields", file_id, builder.finish());
        res.borrow_mut().push(Diagnostic {
            range: d.highlight_range(),
            message: d.message(),
            severity: Severity::Error,
            fix: Some(fix),
        })
    });
    if let Some(m) = source_binder::module_from_file_id(db, file_id) {
        m.diagnostics(db, &mut sink);
    };
    drop(sink);
    res.into_inner()
}
fn location_to_range(location: Location) -> TextRange {
    match location {
        Location::Offset(offset) => TextRange::offset_len(offset, 1.into()),
        Location::Range(range) => range,
    }
}

fn check_unnecessary_braces_in_use_statement(
    acc: &mut Vec<Diagnostic>,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<()> {
    let use_tree_list = ast::UseTreeList::cast(node)?;
    if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
        let range = use_tree_list.syntax().range();
        let edit =
            text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(single_use_tree)
                .unwrap_or_else(|| {
                    let to_replace = single_use_tree.syntax().text().to_string();
                    let mut edit_builder = TextEditBuilder::default();
                    edit_builder.delete(range);
                    edit_builder.insert(range.start(), to_replace);
                    edit_builder.finish()
                });

        acc.push(Diagnostic {
            range,
            message: format!("Unnecessary braces in use statement"),
            severity: Severity::WeakWarning,
            fix: Some(SourceChange::source_file_edit(
                "Remove unnecessary braces",
                SourceFileEdit { file_id, edit },
            )),
        });
    }

    Some(())
}

fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
    single_use_tree: &ast::UseTree,
) -> Option<TextEdit> {
    let use_tree_list_node = single_use_tree.syntax().parent()?;
    if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind() == T![self] {
        let start = use_tree_list_node.prev_sibling_or_token()?.range().start();
        let end = use_tree_list_node.range().end();
        let range = TextRange::from_to(start, end);
        let mut edit_builder = TextEditBuilder::default();
        edit_builder.delete(range);
        return Some(edit_builder.finish());
    }
    None
}

fn check_struct_shorthand_initialization(
    acc: &mut Vec<Diagnostic>,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<()> {
    let struct_lit = ast::StructLit::cast(node)?;
    let named_field_list = struct_lit.named_field_list()?;
    for named_field in named_field_list.fields() {
        if let (Some(name_ref), Some(expr)) = (named_field.name_ref(), named_field.expr()) {
            let field_name = name_ref.syntax().text().to_string();
            let field_expr = expr.syntax().text().to_string();
            if field_name == field_expr {
                let mut edit_builder = TextEditBuilder::default();
                edit_builder.delete(named_field.syntax().range());
                edit_builder.insert(named_field.syntax().range().start(), field_name);
                let edit = edit_builder.finish();

                acc.push(Diagnostic {
                    range: named_field.syntax().range(),
                    message: format!("Shorthand struct initialization"),
                    severity: Severity::WeakWarning,
                    fix: Some(SourceChange::source_file_edit(
                        "use struct shorthand initialization",
                        SourceFileEdit { file_id, edit },
                    )),
                });
            }
        }
    }
    Some(())
}

#[cfg(test)]
mod tests {
    use test_utils::assert_eq_text;
    use insta::assert_debug_snapshot_matches;
    use ra_syntax::SourceFile;

    use crate::mock_analysis::single_file;

    use super::*;

    type DiagnosticChecker = fn(&mut Vec<Diagnostic>, FileId, &SyntaxNode) -> Option<()>;

    fn check_not_applicable(code: &str, func: DiagnosticChecker) {
        let file = SourceFile::parse(code).tree;
        let mut diagnostics = Vec::new();
        for node in file.syntax().descendants() {
            func(&mut diagnostics, FileId(0), node);
        }
        assert!(diagnostics.is_empty());
    }

    fn check_apply(before: &str, after: &str, func: DiagnosticChecker) {
        let file = SourceFile::parse(before).tree;
        let mut diagnostics = Vec::new();
        for node in file.syntax().descendants() {
            func(&mut diagnostics, FileId(0), node);
        }
        let diagnostic =
            diagnostics.pop().unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before));
        let mut fix = diagnostic.fix.unwrap();
        let edit = fix.source_file_edits.pop().unwrap().edit;
        let actual = edit.apply(&before);
        assert_eq_text!(after, &actual);
    }

    fn check_apply_diagnostic_fix(before: &str, after: &str) {
        let (analysis, file_id) = single_file(before);
        let diagnostic = analysis.diagnostics(file_id).unwrap().pop().unwrap();
        let mut fix = diagnostic.fix.unwrap();
        let edit = fix.source_file_edits.pop().unwrap().edit;
        let actual = edit.apply(&before);
        assert_eq_text!(after, &actual);
    }

    fn check_no_diagnostic(content: &str) {
        let (analysis, file_id) = single_file(content);
        let diagnostics = analysis.diagnostics(file_id).unwrap();
        assert_eq!(diagnostics.len(), 0);
    }

    #[test]
    fn test_fill_struct_fields_empty() {
        let before = r"
            struct TestStruct {
                one: i32,
                two: i64,
            }

            fn test_fn() {
                let s = TestStruct{};
            }
        ";
        let after = r"
            struct TestStruct {
                one: i32,
                two: i64,
            }

            fn test_fn() {
                let s = TestStruct{ one: (), two: ()};
            }
        ";
        check_apply_diagnostic_fix(before, after);
    }

    #[test]
    fn test_fill_struct_fields_partial() {
        let before = r"
            struct TestStruct {
                one: i32,
                two: i64,
            }

            fn test_fn() {
                let s = TestStruct{ two: 2 };
            }
        ";
        let after = r"
            struct TestStruct {
                one: i32,
                two: i64,
            }

            fn test_fn() {
                let s = TestStruct{ two: 2, one: () };
            }
        ";
        check_apply_diagnostic_fix(before, after);
    }

    #[test]
    fn test_fill_struct_fields_no_diagnostic() {
        let content = r"
            struct TestStruct {
                one: i32,
                two: i64,
            }

            fn test_fn() {
                let one = 1;
                let s = TestStruct{ one, two: 2 };
            }
        ";

        check_no_diagnostic(content);
    }

    #[test]
    fn test_fill_struct_fields_no_diagnostic_on_spread() {
        let content = r"
            struct TestStruct {
                one: i32,
                two: i64,
            }

            fn test_fn() {
                let one = 1;
                let s = TestStruct{ ..a };
            }
        ";

        check_no_diagnostic(content);
    }

    #[test]
    fn test_unresolved_module_diagnostic() {
        let (analysis, file_id) = single_file("mod foo;");
        let diagnostics = analysis.diagnostics(file_id).unwrap();
        assert_debug_snapshot_matches!(diagnostics, @r###"
       ⋮[
       ⋮    Diagnostic {
       ⋮        message: "unresolved module",
       ⋮        range: [0; 8),
       ⋮        fix: Some(
       ⋮            SourceChange {
       ⋮                label: "create module",
       ⋮                source_file_edits: [],
       ⋮                file_system_edits: [
       ⋮                    CreateFile {
       ⋮                        source_root: SourceRootId(
       ⋮                            0,
       ⋮                        ),
       ⋮                        path: "foo.rs",
       ⋮                    },
       ⋮                ],
       ⋮                cursor_position: None,
       ⋮            },
       ⋮        ),
       ⋮        severity: Error,
       ⋮    },
       ⋮]
        "###);
    }

    #[test]
    fn test_check_unnecessary_braces_in_use_statement() {
        check_not_applicable(
            "
            use a;
            use a::{c, d::e};
        ",
            check_unnecessary_braces_in_use_statement,
        );
        check_apply("use {b};", "use b;", check_unnecessary_braces_in_use_statement);
        check_apply("use a::{c};", "use a::c;", check_unnecessary_braces_in_use_statement);
        check_apply("use a::{self};", "use a;", check_unnecessary_braces_in_use_statement);
        check_apply(
            "use a::{c, d::{e}};",
            "use a::{c, d::e};",
            check_unnecessary_braces_in_use_statement,
        );
    }

    #[test]
    fn test_check_struct_shorthand_initialization() {
        check_not_applicable(
            r#"
            struct A {
                a: &'static str
            }

            fn main() {
                A {
                    a: "hello"
                }
            }
        "#,
            check_struct_shorthand_initialization,
        );

        check_apply(
            r#"
struct A {
    a: &'static str
}

fn main() {
    let a = "haha";
    A {
        a: a
    }
}
        "#,
            r#"
struct A {
    a: &'static str
}

fn main() {
    let a = "haha";
    A {
        a
    }
}
        "#,
            check_struct_shorthand_initialization,
        );

        check_apply(
            r#"
struct A {
    a: &'static str,
    b: &'static str
}

fn main() {
    let a = "haha";
    let b = "bb";
    A {
        a: a,
        b
    }
}
        "#,
            r#"
struct A {
    a: &'static str,
    b: &'static str
}

fn main() {
    let a = "haha";
    let b = "bb";
    A {
        a,
        b
    }
}
        "#,
            check_struct_shorthand_initialization,
        );
    }
}
<commit_msg>fix todo<commit_after>use std::cell::RefCell;

use itertools::Itertools;
use hir::{source_binder, diagnostics::{Diagnostic as _, DiagnosticSink}};
use ra_db::SourceDatabase;
use ra_syntax::{
    T, Location, TextRange, SyntaxNode,
    ast::{self, AstNode, NamedFieldList, NamedField},
};
use ra_assists::ast_editor::{AstEditor, AstBuilder};
use ra_text_edit::{TextEdit, TextEditBuilder};
use ra_prof::profile;

use crate::{Diagnostic, FileId, FileSystemEdit, SourceChange, SourceFileEdit, db::RootDatabase};

#[derive(Debug, Copy, Clone)]
pub enum Severity {
    Error,
    WeakWarning,
}

pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> {
    let _p = profile("diagnostics");
    let parse = db.parse(file_id);
    let mut res = Vec::new();

    res.extend(parse.errors.iter().map(|err| Diagnostic {
        range: location_to_range(err.location()),
        message: format!("Syntax Error: {}", err),
        severity: Severity::Error,
        fix: None,
    }));

    let source_file = parse.tree;

    for node in source_file.syntax().descendants() {
        check_unnecessary_braces_in_use_statement(&mut res, file_id, node);
        check_struct_shorthand_initialization(&mut res, file_id, node);
    }
    let res = RefCell::new(res);
    let mut sink = DiagnosticSink::new(|d| {
        res.borrow_mut().push(Diagnostic {
            message: d.message(),
            range: d.highlight_range(),
            severity: Severity::Error,
            fix: None,
        })
    })
    .on::<hir::diagnostics::UnresolvedModule, _>(|d| {
        let source_root = db.file_source_root(d.file().original_file(db));
        let create_file = FileSystemEdit::CreateFile { source_root, path: d.candidate.clone() };
        let fix = SourceChange::file_system_edit("create module", create_file);
        res.borrow_mut().push(Diagnostic {
            range: d.highlight_range(),
            message: d.message(),
            severity: Severity::Error,
            fix: Some(fix),
        })
    })
    .on::<hir::diagnostics::MissingFields, _>(|d| {
        let syntax_node = d.syntax_node_ptr();
        let node = NamedFieldList::cast(syntax_node.to_node(source_file.syntax())).unwrap();
        let mut ast_editor = AstEditor::new(node);
        for f in d.missed_fields.iter() {
            ast_editor.append_field(&AstBuilder::<NamedField>::from_name(f));
        }

        let mut builder = TextEditBuilder::default();
        ast_editor.into_text_edit(&mut builder);
        let fix =
            SourceChange::source_file_edit_from("fill struct fields", file_id, builder.finish());
        res.borrow_mut().push(Diagnostic {
            range: d.highlight_range(),
            message: d.message(),
            severity: Severity::Error,
            fix: Some(fix),
        })
    });
    if let Some(m) = source_binder::module_from_file_id(db, file_id) {
        m.diagnostics(db, &mut sink);
    };
    drop(sink);
    res.into_inner()
}
fn location_to_range(location: Location) -> TextRange {
    match location {
        Location::Offset(offset) => TextRange::offset_len(offset, 1.into()),
        Location::Range(range) => range,
    }
}

fn check_unnecessary_braces_in_use_statement(
    acc: &mut Vec<Diagnostic>,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<()> {
    let use_tree_list = ast::UseTreeList::cast(node)?;
    if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
        let range = use_tree_list.syntax().range();
        let edit =
            text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(single_use_tree)
                .unwrap_or_else(|| {
                    let to_replace = single_use_tree.syntax().text().to_string();
                    let mut edit_builder = TextEditBuilder::default();
                    edit_builder.delete(range);
                    edit_builder.insert(range.start(), to_replace);
                    edit_builder.finish()
                });

        acc.push(Diagnostic {
            range,
            message: format!("Unnecessary braces in use statement"),
            severity: Severity::WeakWarning,
            fix: Some(SourceChange::source_file_edit(
                "Remove unnecessary braces",
                SourceFileEdit { file_id, edit },
            )),
        });
    }

    Some(())
}

fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
    single_use_tree: &ast::UseTree,
) -> Option<TextEdit> {
    let use_tree_list_node = single_use_tree.syntax().parent()?;
    if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind() == T![self] {
        let start = use_tree_list_node.prev_sibling_or_token()?.range().start();
        let end = use_tree_list_node.range().end();
        let range = TextRange::from_to(start, end);
        let mut edit_builder = TextEditBuilder::default();
        edit_builder.delete(range);
        return Some(edit_builder.finish());
    }
    None
}

fn check_struct_shorthand_initialization(
    acc: &mut Vec<Diagnostic>,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<()> {
    let struct_lit = ast::StructLit::cast(node)?;
    let named_field_list = struct_lit.named_field_list()?;
    for named_field in named_field_list.fields() {
        if let (Some(name_ref), Some(expr)) = (named_field.name_ref(), named_field.expr()) {
            let field_name = name_ref.syntax().text().to_string();
            let field_expr = expr.syntax().text().to_string();
            if field_name == field_expr {
                let mut edit_builder = TextEditBuilder::default();
                edit_builder.delete(named_field.syntax().range());
                edit_builder.insert(named_field.syntax().range().start(), field_name);
                let edit = edit_builder.finish();

                acc.push(Diagnostic {
                    range: named_field.syntax().range(),
                    message: format!("Shorthand struct initialization"),
                    severity: Severity::WeakWarning,
                    fix: Some(SourceChange::source_file_edit(
                        "use struct shorthand initialization",
                        SourceFileEdit { file_id, edit },
                    )),
                });
            }
        }
    }
    Some(())
}

#[cfg(test)]
mod tests {
    use test_utils::assert_eq_text;
    use insta::assert_debug_snapshot_matches;
    use ra_syntax::SourceFile;

    use crate::mock_analysis::single_file;

    use super::*;

    type DiagnosticChecker = fn(&mut Vec<Diagnostic>, FileId, &SyntaxNode) -> Option<()>;

    fn check_not_applicable(code: &str, func: DiagnosticChecker) {
        let file = SourceFile::parse(code).tree;
        let mut diagnostics = Vec::new();
        for node in file.syntax().descendants() {
            func(&mut diagnostics, FileId(0), node);
        }
        assert!(diagnostics.is_empty());
    }

    fn check_apply(before: &str, after: &str, func: DiagnosticChecker) {
        let file = SourceFile::parse(before).tree;
        let mut diagnostics = Vec::new();
        for node in file.syntax().descendants() {
            func(&mut diagnostics, FileId(0), node);
        }
        let diagnostic =
            diagnostics.pop().unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before));
        let mut fix = diagnostic.fix.unwrap();
        let edit = fix.source_file_edits.pop().unwrap().edit;
        let actual = edit.apply(&before);
        assert_eq_text!(after, &actual);
    }

    fn check_apply_diagnostic_fix(before: &str, after: &str) {
        let (analysis, file_id) = single_file(before);
        let diagnostic = analysis.diagnostics(file_id).unwrap().pop().unwrap();
        let mut fix = diagnostic.fix.unwrap();
        let edit = fix.source_file_edits.pop().unwrap().edit;
        let actual = edit.apply(&before);
        assert_eq_text!(after, &actual);
    }

    fn check_no_diagnostic(content: &str) {
        let (analysis, file_id) = single_file(content);
        let diagnostics = analysis.diagnostics(file_id).unwrap();
        assert_eq!(diagnostics.len(), 0);
    }

    #[test]
    fn test_fill_struct_fields_empty() {
        let before = r"
            struct TestStruct {
                one: i32,
                two: i64,
            }

            fn test_fn() {
                let s = TestStruct{};
            }
        ";
        let after = r"
            struct TestStruct {
                one: i32,
                two: i64,
            }

            fn test_fn() {
                let s = TestStruct{ one: (), two: ()};
            }
        ";
        check_apply_diagnostic_fix(before, after);
    }

    #[test]
    fn test_fill_struct_fields_partial() {
        let before = r"
            struct TestStruct {
                one: i32,
                two: i64,
            }

            fn test_fn() {
                let s = TestStruct{ two: 2 };
            }
        ";
        let after = r"
            struct TestStruct {
                one: i32,
                two: i64,
            }

            fn test_fn() {
                let s = TestStruct{ two: 2, one: () };
            }
        ";
        check_apply_diagnostic_fix(before, after);
    }

    #[test]
    fn test_fill_struct_fields_no_diagnostic() {
        let content = r"
            struct TestStruct {
                one: i32,
                two: i64,
            }

            fn test_fn() {
                let one = 1;
                let s = TestStruct{ one, two: 2 };
            }
        ";

        check_no_diagnostic(content);
    }

    #[test]
    fn test_fill_struct_fields_no_diagnostic_on_spread() {
        let content = r"
            struct TestStruct {
                one: i32,
                two: i64,
            }

            fn test_fn() {
                let one = 1;
                let s = TestStruct{ ..a };
            }
        ";

        check_no_diagnostic(content);
    }

    #[test]
    fn test_unresolved_module_diagnostic() {
        let (analysis, file_id) = single_file("mod foo;");
        let diagnostics = analysis.diagnostics(file_id).unwrap();
        assert_debug_snapshot_matches!(diagnostics, @r###"
       ⋮[
       ⋮    Diagnostic {
       ⋮        message: "unresolved module",
       ⋮        range: [0; 8),
       ⋮        fix: Some(
       ⋮            SourceChange {
       ⋮                label: "create module",
       ⋮                source_file_edits: [],
       ⋮                file_system_edits: [
       ⋮                    CreateFile {
       ⋮                        source_root: SourceRootId(
       ⋮                            0,
       ⋮                        ),
       ⋮                        path: "foo.rs",
       ⋮                    },
       ⋮                ],
       ⋮                cursor_position: None,
       ⋮            },
       ⋮        ),
       ⋮        severity: Error,
       ⋮    },
       ⋮]
        "###);
    }

    #[test]
    fn test_check_unnecessary_braces_in_use_statement() {
        check_not_applicable(
            "
            use a;
            use a::{c, d::e};
        ",
            check_unnecessary_braces_in_use_statement,
        );
        check_apply("use {b};", "use b;", check_unnecessary_braces_in_use_statement);
        check_apply("use a::{c};", "use a::c;", check_unnecessary_braces_in_use_statement);
        check_apply("use a::{self};", "use a;", check_unnecessary_braces_in_use_statement);
        check_apply(
            "use a::{c, d::{e}};",
            "use a::{c, d::e};",
            check_unnecessary_braces_in_use_statement,
        );
    }

    #[test]
    fn test_check_struct_shorthand_initialization() {
        check_not_applicable(
            r#"
            struct A {
                a: &'static str
            }

            fn main() {
                A {
                    a: "hello"
                }
            }
        "#,
            check_struct_shorthand_initialization,
        );

        check_apply(
            r#"
struct A {
    a: &'static str
}

fn main() {
    let a = "haha";
    A {
        a: a
    }
}
        "#,
            r#"
struct A {
    a: &'static str
}

fn main() {
    let a = "haha";
    A {
        a
    }
}
        "#,
            check_struct_shorthand_initialization,
        );

        check_apply(
            r#"
struct A {
    a: &'static str,
    b: &'static str
}

fn main() {
    let a = "haha";
    let b = "bb";
    A {
        a: a,
        b
    }
}
        "#,
            r#"
struct A {
    a: &'static str,
    b: &'static str
}

fn main() {
    let a = "haha";
    let b = "bb";
    A {
        a,
        b
    }
}
        "#,
            check_struct_shorthand_initialization,
        );
    }
}
<|endoftext|>


<commit_before>use lib::alias_dist::AliasDistribution;
use lib::error::MarkovpassError;
use std::collections::HashMap;

struct MarkovChainIterator<'a> {
    markov_chain: &'a PassphraseMarkovChain<'a>,
    current: &'a str,
}

impl<'a> Iterator for MarkovChainIterator<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        let last = self.current;
        self.current = self.markov_chain.get_next_ngram(&self.current);

        Some(last)
    }
}

#[derive(Debug)]
struct MarkovNode<T> {
    pub value: T,
    transitions: Vec<T>,
    dist: AliasDistribution,
}

impl<T> MarkovNode<T> {
    pub fn new(value: T, values: Vec<T>, weights: Vec<f64>) -> MarkovNode<T> {
        MarkovNode {
            value: value,
            transitions: values,
            dist: AliasDistribution::new(&weights).unwrap(),
        }
    }

    pub fn next(&self) -> &T {
        &self.transitions[self.dist.choice()]
    }

    pub fn entropy(&self) -> f64 {
        self.dist.entropy
    }
}

#[derive(Debug)]
pub struct PassphraseMarkovChain<'a> {
    nodes: HashMap<&'a str, MarkovNode<&'a str>>,
    starting_ngrams: Vec<&'a str>,
    starting_dist: AliasDistribution,
}

impl<'a> PassphraseMarkovChain<'a> {
    pub fn new(ngrams: Vec<&'a str>) -> Result<PassphraseMarkovChain, MarkovpassError> {
        // Count transitions and viable starting ngrams.
        // To get natural sounding words, starting ngrams should be at word start.
        let mut transition_counters: HashMap<&str, HashMap<&str, usize>> = HashMap::new();
        let mut starting_ngram_counts: HashMap<&str, usize> = HashMap::new();

        if ngrams.len() == 0 {
            return Err(MarkovpassError::NoNgrams);
        }
        let mut a = ngrams[0].clone();
        for b in ngrams
            .into_iter()
            .skip(1)
            .chain(Some(a.clone()).into_iter())
        {
            if a.starts_with(" ") {
                *starting_ngram_counts.entry(a.clone()).or_insert(0) += 1;
            }
            *transition_counters
                .entry(a)
                .or_insert(HashMap::new())
                .entry(b.clone())
                .or_insert(0) += 1;
            a = b;
        }

        // Generate the starting ngram probability distribution.
        let mut starting_ngrams = Vec::with_capacity(starting_ngram_counts.len());
        let mut weights = Vec::with_capacity(starting_ngram_counts.len());
        for (value, weight) in starting_ngram_counts.into_iter() {
            starting_ngrams.push(value);
            weights.push(weight as f64);
        }
        let starting_dist = AliasDistribution::new(&weights).unwrap();

        // Build all the MarkovNodes from the transition counts.
        let mut nodes: HashMap<&str, MarkovNode<&str>> = HashMap::new();
        let mut total_entropy: f64 = 0.0;
        for (ngram, transition_counts) in transition_counters.into_iter() {
            let mut values = Vec::with_capacity(transition_counts.len());
            let mut weights = Vec::with_capacity(transition_counts.len());
            for (value, weight) in transition_counts.into_iter() {
                values.push(value);
                weights.push(weight as f64);
            }

            let node = MarkovNode::new(ngram.clone(), values, weights);
            total_entropy += node.entropy();
            nodes.insert(ngram, node);
        }

        if total_entropy == 0.0 {
            return Err(MarkovpassError::NoEntropy);
        } else if starting_dist.entropy == 0.0 {
            return Err(MarkovpassError::NoStartOfWordEntropy);
        };

        Ok(PassphraseMarkovChain {
            nodes: nodes,
            starting_ngrams: starting_ngrams,
            starting_dist: starting_dist,
        })
    }

    pub fn passphrase(&self, min_entropy: f64) -> (String, f64) {
        let mut selected_ngrams = Vec::new();
        let mut entropy = self.starting_dist.entropy;

        for ngram in self.iter() {
            selected_ngrams.push(ngram.clone());
            entropy += self.ngram_entropy(&ngram);
            if entropy >= min_entropy && ngram.ends_with(" ") {
                break;
            }
        }

        // Include the first character from each ngram, and the whole final ngram.
        let tail = selected_ngrams.last().unwrap().chars().skip(1);
        let chars = selected_ngrams
            .iter()
            .map(|n| n.chars().next().unwrap())
            .chain(tail);
        let passphrase = chars.collect::<String>().trim().to_string();

        (passphrase, entropy)
    }

    fn iter(&self) -> MarkovChainIterator {
        MarkovChainIterator {
            markov_chain: &self,
            current: &self.get_starting_ngram(),
        }
    }

    fn get_starting_ngram(&self) -> &str {
        &self
            .nodes
            .get(&self.starting_ngrams[self.starting_dist.choice()])
            .unwrap()
            .value
    }

    fn get_next_ngram(&self, ngram: &str) -> &str {
        self.nodes.get(ngram).unwrap().next()
    }

    fn ngram_entropy(&self, ngram: &str) -> f64 {
        self.nodes.get(ngram).unwrap().entropy()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_passphrasemarkovchain_new() {
        let ngrams = vec![" ti", "tic", "ic ", "c t", " to", "toc", "oc ", "c t"];
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_ok());
        let chain = result.unwrap();
        assert_eq!(chain.starting_ngrams.len(), 2);
        assert!(chain.starting_ngrams.contains(&" ti"));
        assert!(chain.starting_ngrams.contains(&" to"));
        assert_eq!(chain.starting_dist.entropy, 1.0);
        assert!(ngrams.contains(&chain.get_starting_ngram()));
        let (p, e) = chain.passphrase(60.0);
        assert_eq!(e, 60.0);
        assert_eq!(p.len(), 239);
    }

    #[test]
    fn test_passphrase_no_ngrams() {
        let ngrams: Vec<&str> = vec![];
        let result = PassphraseMarkovChain::new(ngrams);
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoNgrams);
    }

    #[test]
    fn test_passphrase_no_entropy() {
        let ngrams = vec![" ab", "abc", "bcd", "cd ", "d a"];
        let result = PassphraseMarkovChain::new(ngrams);
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoEntropy);
    }

    #[test]
    fn test_passphrases_no_starting_entropy() {
        let ngrams = vec![
            " ab", "abc", "bc ", "c a", " ab", "abc", "cbd", "bd ", "d a",
        ];
        let result = PassphraseMarkovChain::new(ngrams);
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoStartOfWordEntropy);
    }
}
<commit_msg>Tidy up markovchain code now that it's all &strs<commit_after>use lib::alias_dist::AliasDistribution;
use lib::error::MarkovpassError;
use std::collections::HashMap;

struct MarkovChainIterator<'a> {
    markov_chain: &'a PassphraseMarkovChain<'a>,
    current: &'a str,
}

impl<'a> Iterator for MarkovChainIterator<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        let last = self.current;
        self.current = self.markov_chain.get_next_ngram(&self.current);

        Some(last)
    }
}

#[derive(Debug)]
struct MarkovNode<T> {
    pub value: T,
    transitions: Vec<T>,
    dist: AliasDistribution,
}

impl<T> MarkovNode<T> {
    pub fn new(value: T, values: Vec<T>, weights: Vec<f64>) -> MarkovNode<T> {
        MarkovNode {
            value: value,
            transitions: values,
            dist: AliasDistribution::new(&weights).unwrap(),
        }
    }

    pub fn next(&self) -> &T {
        &self.transitions[self.dist.choice()]
    }

    pub fn entropy(&self) -> f64 {
        self.dist.entropy
    }
}

#[derive(Debug)]
pub struct PassphraseMarkovChain<'a> {
    nodes: HashMap<&'a str, MarkovNode<&'a str>>,
    starting_ngrams: Vec<&'a str>,
    starting_dist: AliasDistribution,
}

impl<'a> PassphraseMarkovChain<'a> {
    pub fn new(ngrams: Vec<&'a str>) -> Result<PassphraseMarkovChain, MarkovpassError> {
        // Count transitions and viable starting ngrams.
        // To get natural sounding words, starting ngrams should be at word start.
        let mut transition_counters: HashMap<&str, HashMap<&str, usize>> = HashMap::new();
        let mut starting_ngram_counts: HashMap<&str, usize> = HashMap::new();

        if ngrams.len() == 0 {
            return Err(MarkovpassError::NoNgrams);
        }
        for (a, b) in ngrams
            .iter()
            .zip(ngrams.iter().skip(1).chain(Some(&ngrams[0])))
        {
            if a.starts_with(" ") {
                *starting_ngram_counts.entry(a).or_insert(0) += 1;
            }
            *transition_counters
                .entry(a)
                .or_insert(HashMap::new())
                .entry(b)
                .or_insert(0) += 1;
        }

        // Generate the starting ngram probability distribution.
        let mut starting_ngrams = Vec::with_capacity(starting_ngram_counts.len());
        let mut starting_ngram_weights = Vec::with_capacity(starting_ngram_counts.len());
        for (value, weight) in starting_ngram_counts.into_iter() {
            starting_ngrams.push(value);
            starting_ngram_weights.push(weight as f64);
        }
        let starting_dist = AliasDistribution::new(&starting_ngram_weights).unwrap();

        // Build all the MarkovNodes from the transition counts.
        let mut nodes: HashMap<&str, MarkovNode<&str>> = HashMap::new();
        let mut total_entropy: f64 = 0.0;
        for (ngram, transition_counts) in transition_counters.into_iter() {
            let mut values = Vec::with_capacity(transition_counts.len());
            let mut weights = Vec::with_capacity(transition_counts.len());
            for (value, weight) in transition_counts.into_iter() {
                values.push(value);
                weights.push(weight as f64);
            }

            let node = MarkovNode::new(ngram, values, weights);
            total_entropy += node.entropy();
            nodes.insert(ngram, node);
        }

        if total_entropy == 0.0 {
            return Err(MarkovpassError::NoEntropy);
        } else if starting_dist.entropy == 0.0 {
            return Err(MarkovpassError::NoStartOfWordEntropy);
        };

        Ok(PassphraseMarkovChain {
            nodes: nodes,
            starting_ngrams: starting_ngrams,
            starting_dist: starting_dist,
        })
    }

    pub fn passphrase(&self, min_entropy: f64) -> (String, f64) {
        let mut selected_ngrams = Vec::new();
        let mut entropy = self.starting_dist.entropy;

        for ngram in self.iter() {
            selected_ngrams.push(ngram.clone());
            entropy += self.ngram_entropy(&ngram);
            if entropy >= min_entropy && ngram.ends_with(" ") {
                break;
            }
        }

        // Include the first character from each ngram, and the whole final ngram.
        let tail = selected_ngrams.last().unwrap().chars().skip(1);
        let chars = selected_ngrams
            .iter()
            .map(|n| n.chars().next().unwrap())
            .chain(tail);
        let passphrase = chars.collect::<String>().trim().to_string();

        (passphrase, entropy)
    }

    fn iter(&self) -> MarkovChainIterator {
        MarkovChainIterator {
            markov_chain: &self,
            current: &self.get_starting_ngram(),
        }
    }

    fn get_starting_ngram(&self) -> &str {
        &self
            .nodes
            .get(&self.starting_ngrams[self.starting_dist.choice()])
            .unwrap()
            .value
    }

    fn get_next_ngram(&self, ngram: &str) -> &str {
        self.nodes.get(ngram).unwrap().next()
    }

    fn ngram_entropy(&self, ngram: &str) -> f64 {
        self.nodes.get(ngram).unwrap().entropy()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_passphrasemarkovchain_new() {
        let ngrams = vec![" ti", "tic", "ic ", "c t", " to", "toc", "oc ", "c t"];
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_ok());
        let chain = result.unwrap();
        assert_eq!(chain.starting_ngrams.len(), 2);
        assert!(chain.starting_ngrams.contains(&" ti"));
        assert!(chain.starting_ngrams.contains(&" to"));
        assert_eq!(chain.starting_dist.entropy, 1.0);
        assert!(ngrams.contains(&chain.get_starting_ngram()));
        let (p, e) = chain.passphrase(60.0);
        assert_eq!(e, 60.0);
        assert_eq!(p.len(), 239);
    }

    #[test]
    fn test_passphrase_no_ngrams() {
        let ngrams: Vec<&str> = vec![];
        let result = PassphraseMarkovChain::new(ngrams);
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoNgrams);
    }

    #[test]
    fn test_passphrase_no_entropy() {
        let ngrams = vec![" ab", "abc", "bcd", "cd ", "d a"];
        let result = PassphraseMarkovChain::new(ngrams);
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoEntropy);
    }

    #[test]
    fn test_passphrases_no_starting_entropy() {
        let ngrams = vec![
            " ab", "abc", "bc ", "c a", " ab", "abc", "cbd", "bd ", "d a",
        ];
        let result = PassphraseMarkovChain::new(ngrams);
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoStartOfWordEntropy);
    }
}
<|endoftext|>


<commit_before>/// A collection of miscellaneous methods for `&str`.
pub trait StrUtil {
    /// Returns a `String` between `delim_a` and `delim_b`.
    ///
    /// # Example
    ///
    /// ```
    /// use twirc::util::string::StrUtil;
    ///
    /// println!("{:?}", "a:selected_string!garbage".between(":", "!"));
    /// ```
    fn between(&self, delim_a: &str, delim_b: &str) -> Result<String, String>;

    /// Returns the portion of a `&str` that occurs after `delim`.
    ///
    /// # Example
    ///
    /// ```
    /// use twirc::util::string::StrUtil;
    ///
    /// println!("{:?}", ":garbage :selected_string".after(" :"));
    /// ```
    fn after(&self, delim: &str) -> Result<String, String>;
}

impl StrUtil for str {
    fn between(&self, delim_a: &str, delim_b: &str) -> Result<String, String> {
        let start_idx =
            self
            .find(delim_a)
            .ok_or(format!("between(): start string \"{}\" not found", delim_a))?;

        let start_str = &self[start_idx + delim_a.len()..];

        let end =
            start_str
            .find(delim_b)
            .ok_or(format!("between(): end string \"{}\" not found", delim_b))?;

        Ok(start_str[..end].to_string())
    }

    fn after(&self, delim: &str) -> Result<String, String> {
        self
        .find(delim)
        .map(|i| self[i + delim.len()..].to_string())
        .ok_or(format!("after(): string delimiter \"{}\" not found", delim))
    }
}<commit_msg>Make error locations slightly more specific<commit_after>/// A collection of miscellaneous methods for `&str`.
pub trait StrUtil {
    /// Returns a `String` between `delim_a` and `delim_b`.
    ///
    /// # Example
    ///
    /// ```
    /// use twirc::util::string::StrUtil;
    ///
    /// println!("{:?}", "a:selected_string!garbage".between(":", "!"));
    /// ```
    fn between(&self, delim_a: &str, delim_b: &str) -> Result<String, String>;

    /// Returns the portion of a `&str` that occurs after `delim`.
    ///
    /// # Example
    ///
    /// ```
    /// use twirc::util::string::StrUtil;
    ///
    /// println!("{:?}", ":garbage :selected_string".after(" :"));
    /// ```
    fn after(&self, delim: &str) -> Result<String, String>;
}

impl StrUtil for str {
    fn between(&self, delim_a: &str, delim_b: &str) -> Result<String, String> {
        let start_idx =
            self
            .find(delim_a)
            .ok_or(format!("util::string::between(): start string \"{}\" not found", delim_a))?;

        let start_str = &self[start_idx + delim_a.len()..];

        let end =
            start_str
            .find(delim_b)
            .ok_or(format!("util::string::between(): end string \"{}\" not found", delim_b))?;

        Ok(start_str[..end].to_string())
    }

    fn after(&self, delim: &str) -> Result<String, String> {
        self
        .find(delim)
        .map(|i| self[i + delim.len()..].to_string())
        .ok_or(format!("util::string::after(): string delimiter \"{}\" not found", delim))
    }
}<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Traits for conversions between types.
//!
//! The traits in this module provide a general way to talk about
//! conversions from one type to another. They follow the standard
//! Rust conventions of `as`/`to`/`into`/`from`.

#![stable(feature = "rust1", since = "1.0.0")]

use marker::Sized;

/// A cheap, reference-to-reference conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_ref(&self) -> &T;
}

/// A cheap, mutable reference-to-mutable reference conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_mut(&mut self) -> &mut T;
}

/// A conversion that consumes `self`, which may or may not be
/// expensive.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into(self) -> T;
}

/// Construct `Self` via a conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from(T) -> Self;
}

////////////////////////////////////////////////////////////////////////////////
// GENERIC IMPLS
////////////////////////////////////////////////////////////////////////////////

// As lifts over &
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// As lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// FIXME (#23442): replace the above impls for &/&mut with the following more general one:
// // As lifts over Deref
// impl<D: ?Sized + Deref, U: ?Sized> AsRef<U> for D where D::Target: AsRef<U> {
//     fn as_ref(&self) -> &U {
//         self.deref().as_ref()
//     }
// }

// AsMut lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
    fn as_mut(&mut self) -> &mut U {
        (*self).as_mut()
    }
}

// FIXME (#23442): replace the above impl for &mut with the following more general one:
// // AsMut lifts over DerefMut
// impl<D: ?Sized + Deref, U: ?Sized> AsMut<U> for D where D::Target: AsMut<U> {
//     fn as_mut(&mut self) -> &mut U {
//         self.deref_mut().as_mut()
//     }
// }

// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T where U: From<T> {
    fn into(self) -> U {
        U::from(self)
    }
}

// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<T> for T {
    fn from(t: T) -> T { t }
}

////////////////////////////////////////////////////////////////////////////////
// CONCRETE IMPLS
////////////////////////////////////////////////////////////////////////////////

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for [T] {
    fn as_ref(&self) -> &[T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T] {
    fn as_mut(&mut self) -> &mut [T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<str> for str {
    fn as_ref(&self) -> &str {
        self
    }
}
<commit_msg>Rollup merge of #24121 - steveklabnik:gh24107, r=steveklabnik<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Traits for conversions between types.
//!
//! The traits in this module provide a general way to talk about conversions from one type to
//! another. They follow the standard Rust conventions of `as`/`to`/`into`/`from`.
//!
//! Like many traits, these are often used as bounds for generic functions, to support arguments of
//! multiple types.
//!
//! See each trait for usage examples.

#![stable(feature = "rust1", since = "1.0.0")]

use marker::Sized;

/// A cheap, reference-to-reference conversion.
///
/// # Examples
///
/// Both `String` and `&str` implement `AsRef<str>`:
///
/// ```
/// fn is_hello<T: AsRef<str>>(s: T) {
///    assert_eq!("hello", s.as_ref());
/// }
///
/// let s = "hello";
/// is_hello(s);
///
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_ref(&self) -> &T;
}

/// A cheap, mutable reference-to-mutable reference conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_mut(&mut self) -> &mut T;
}

/// A conversion that consumes `self`, which may or may not be expensive.
///
/// # Examples
///
/// `String` implements `Into<Vec<u8>>`:
///
/// ```
/// fn is_hello<T: Into<Vec<u8>>>(s: T) {
///    let bytes = b"hello".to_vec();
///    assert_eq!(bytes, s.into());
/// }
///
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into(self) -> T;
}

/// Construct `Self` via a conversion.
///
/// # Examples
///
/// `String` implements `From<&str>`:
///
/// ```
/// let s = "hello";
/// let string = "hello".to_string();
///
/// let other_string: String = From::from(s);
///
/// assert_eq!(string, other_string);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from(T) -> Self;
}

////////////////////////////////////////////////////////////////////////////////
// GENERIC IMPLS
////////////////////////////////////////////////////////////////////////////////

// As lifts over &
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// As lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// FIXME (#23442): replace the above impls for &/&mut with the following more general one:
// // As lifts over Deref
// impl<D: ?Sized + Deref, U: ?Sized> AsRef<U> for D where D::Target: AsRef<U> {
//     fn as_ref(&self) -> &U {
//         self.deref().as_ref()
//     }
// }

// AsMut lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
    fn as_mut(&mut self) -> &mut U {
        (*self).as_mut()
    }
}

// FIXME (#23442): replace the above impl for &mut with the following more general one:
// // AsMut lifts over DerefMut
// impl<D: ?Sized + Deref, U: ?Sized> AsMut<U> for D where D::Target: AsMut<U> {
//     fn as_mut(&mut self) -> &mut U {
//         self.deref_mut().as_mut()
//     }
// }

// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T where U: From<T> {
    fn into(self) -> U {
        U::from(self)
    }
}

// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<T> for T {
    fn from(t: T) -> T { t }
}

////////////////////////////////////////////////////////////////////////////////
// CONCRETE IMPLS
////////////////////////////////////////////////////////////////////////////////

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for [T] {
    fn as_ref(&self) -> &[T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T] {
    fn as_mut(&mut self) -> &mut [T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<str> for str {
    fn as_ref(&self) -> &str {
        self
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! The Rust prelude. Imported into every module by default.

/* Reexported core operators */

pub use either::{Either, Left, Right};
pub use kinds::{Const, Copy, Owned, Durable};
#[cfg(stage0)]
pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not};
#[cfg(not(stage0))]
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop};
pub use ops::{Shl, Shr, Index};
pub use option::{Option, Some, None};
pub use result::{Result, Ok, Err};

/* Reexported functions */

pub use io::{print, println};

/* Reexported types and traits */

pub use clone::Clone;
pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater};
pub use container::{Container, Mutable, Map, Set};
pub use hash::Hash;
pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter};
pub use old_iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter};
pub use old_iter::{ExtendedMutableIter};
pub use iter::Times;
pub use num::{Num, NumCast};
pub use num::{Orderable, Signed, Unsigned, Round};
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
pub use num::{Integer, Fractional, Real, RealExt};
pub use num::{Bitwise, BitCount, Bounded};
pub use num::{Primitive, Int, Float};
pub use path::GenericPath;
pub use path::Path;
pub use path::PosixPath;
pub use path::WindowsPath;
pub use ptr::Ptr;
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
pub use str::{StrSlice, OwnedStr};
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, ToStrConsume};
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
pub use vec::{CopyableVector, ImmutableVector};
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector};
pub use io::{Reader, ReaderUtil, Writer, WriterUtil};

/* Reexported runtime types */
pub use comm::{stream, Port, Chan, GenericChan, GenericSmartChan, GenericPort, Peekable};
pub use task::spawn;

/* Reexported modules */

pub use at_vec;
pub use bool;
pub use cast;
pub use char;
pub use cmp;
pub use either;
pub use f32;
pub use f64;
pub use float;
pub use i16;
pub use i32;
pub use i64;
pub use i8;
pub use int;
pub use io;
pub use iter;
pub use old_iter;
pub use libc;
pub use num;
pub use ops;
pub use option;
pub use os;
pub use path;
pub use comm;
pub use unstable;
pub use ptr;
pub use rand;
pub use result;
pub use str;
pub use sys;
pub use task;
pub use to_str;
pub use u16;
pub use u32;
pub use u64;
pub use u8;
pub use uint;
pub use vec;
<commit_msg>Add core::cmp::Equiv to prelude<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! The Rust prelude. Imported into every module by default.

/* Reexported core operators */

pub use either::{Either, Left, Right};
pub use kinds::{Const, Copy, Owned, Durable};
#[cfg(stage0)]
pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not};
#[cfg(not(stage0))]
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop};
pub use ops::{Shl, Shr, Index};
pub use option::{Option, Some, None};
pub use result::{Result, Ok, Err};

/* Reexported functions */

pub use io::{print, println};

/* Reexported types and traits */

pub use clone::Clone;
pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
pub use container::{Container, Mutable, Map, Set};
pub use hash::Hash;
pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter};
pub use old_iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter};
pub use old_iter::{ExtendedMutableIter};
pub use iter::Times;
pub use num::{Num, NumCast};
pub use num::{Orderable, Signed, Unsigned, Round};
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
pub use num::{Integer, Fractional, Real, RealExt};
pub use num::{Bitwise, BitCount, Bounded};
pub use num::{Primitive, Int, Float};
pub use path::GenericPath;
pub use path::Path;
pub use path::PosixPath;
pub use path::WindowsPath;
pub use ptr::Ptr;
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
pub use str::{StrSlice, OwnedStr};
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, ToStrConsume};
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
pub use vec::{CopyableVector, ImmutableVector};
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector};
pub use io::{Reader, ReaderUtil, Writer, WriterUtil};

/* Reexported runtime types */
pub use comm::{stream, Port, Chan, GenericChan, GenericSmartChan, GenericPort, Peekable};
pub use task::spawn;

/* Reexported modules */

pub use at_vec;
pub use bool;
pub use cast;
pub use char;
pub use cmp;
pub use either;
pub use f32;
pub use f64;
pub use float;
pub use i16;
pub use i32;
pub use i64;
pub use i8;
pub use int;
pub use io;
pub use iter;
pub use old_iter;
pub use libc;
pub use num;
pub use ops;
pub use option;
pub use os;
pub use path;
pub use comm;
pub use unstable;
pub use ptr;
pub use rand;
pub use result;
pub use str;
pub use sys;
pub use task;
pub use to_str;
pub use u16;
pub use u32;
pub use u64;
pub use u8;
pub use uint;
pub use vec;
<|endoftext|>


<commit_before>use std::iter::FromIterator;
use std::convert::From;
use std::str::FromStr;

use pest::prelude::*;

use super::{Rdp, ParseError};
use operations::{self, OperationsResult};
use operations::scope::ScopeStack;

#[derive(Debug, PartialEq, Clone)]
pub struct Program {
    pub root_mod: Module,
}

impl Program {
    pub fn new() -> Program {
        Program {
            root_mod: Module::new(),
        }
    }

    pub fn into_operations(self, global_scope: &mut ScopeStack) -> OperationsResult {
        operations::from_ast(global_scope, self)
    }
}

impl FromStr for Program {
    type Err = ParseError;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = Rdp::new(StringInput::new(input));

        if parser.module() {
            Ok(Program {
                root_mod: parser.module_ast(),
            })
        }
        else {
            let (expected, pos) = parser.expected();
            let (line, col) = parser.input().line_col(pos);
            Err(ParseError {
                line: line,
                col: col,
                expected: expected,
            })
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Module {
    pub body: Block,
}

impl Module {
    pub fn new() -> Module {
        Module {
            body: Block::new(),
        }
    }
}

impl From<Block> for Module {
    fn from(block: Block) -> Self {
        Module {
            body: block
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Statement {
    Comment(String),
    Declaration {
        pattern: Pattern,
        type_def: TypeDefinition,
        expr: Option<Expression>,
    },
    Assignment {
        lhs: Identifier,
        expr: Expression,
    },
    WhileLoop {
        condition: Expression,
        body: Block,
    },
    Expression {
        expr: Expression,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Pattern {
    Identifier(Identifier),
}

#[derive(Debug, PartialEq, Clone)]
pub enum TypeDefinition {
    Name {
        name: Identifier,
    },
    Array {
        type_def: Box<TypeDefinition>,
        size: Option<Expression>,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    ByteLiteral(String),
    Identifier(Identifier),
    Number(Number),
    Call {
        method: Box<Expression>,
        args: CallArgs,
    },
    Access {
        target: Box<Expression>,
        field: Box<Expression>,
    },
    Branch {
        /// Condition to be executed to determine which block
        /// is run
        condition: Box<Expression>,
        /// executed if the condition is non-zero
        body: Block,
        /// (optional) executed if the condition is zero
        otherwise: Option<Block>,
    },
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Identifier(Vec<String>);

impl Identifier {
    // NOTE: Do not implement ::new() for Identifier
    // Having an empty Identifier does not make any sense!

    // Concatenates this identifier with another identifier and returns
    // a new identifier
    pub fn concat<T>(self, other: T) -> Identifier where T: IntoIterator<Item=String> {
        self.into_iter().chain(other).collect()
    }
}

impl FromStr for Identifier {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Identifier(s.split("::").map(|s| s.to_owned()).collect()))
    }
}

impl<'a> From<&'a str> for Identifier {
    fn from(s: &'a str) -> Identifier {
        s.parse().unwrap()
    }
}

impl IntoIterator for Identifier {
    type Item = String;
    type IntoIter = ::std::vec::IntoIter<String>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromIterator<String> for Identifier {
    fn from_iter<I: IntoIterator<Item=String>>(iter: I) -> Self {
        Identifier(iter.into_iter().collect())
    }
}

pub type Block = Vec<Statement>;
pub type Number = i32;
pub type CallArgs = Vec<CallArg>;
pub type CallArg = Expression;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn concat_identifiers() {
        let mut ident = Identifier::from("foo::bar::Bar::spam")
            .concat(Identifier::from("car::bar::star"));

        let concated = Identifier::from("foo::bar::Bar::spam::car::bar::star");

        assert_eq!(ident, concated);
    }
}
<commit_msg>Fixed a warning about a variable being mutable when that was not needed<commit_after>use std::iter::FromIterator;
use std::convert::From;
use std::str::FromStr;

use pest::prelude::*;

use super::{Rdp, ParseError};
use operations::{self, OperationsResult};
use operations::scope::ScopeStack;

#[derive(Debug, PartialEq, Clone)]
pub struct Program {
    pub root_mod: Module,
}

impl Program {
    pub fn new() -> Program {
        Program {
            root_mod: Module::new(),
        }
    }

    pub fn into_operations(self, global_scope: &mut ScopeStack) -> OperationsResult {
        operations::from_ast(global_scope, self)
    }
}

impl FromStr for Program {
    type Err = ParseError;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = Rdp::new(StringInput::new(input));

        if parser.module() {
            Ok(Program {
                root_mod: parser.module_ast(),
            })
        }
        else {
            let (expected, pos) = parser.expected();
            let (line, col) = parser.input().line_col(pos);
            Err(ParseError {
                line: line,
                col: col,
                expected: expected,
            })
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Module {
    pub body: Block,
}

impl Module {
    pub fn new() -> Module {
        Module {
            body: Block::new(),
        }
    }
}

impl From<Block> for Module {
    fn from(block: Block) -> Self {
        Module {
            body: block
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Statement {
    Comment(String),
    Declaration {
        pattern: Pattern,
        type_def: TypeDefinition,
        expr: Option<Expression>,
    },
    Assignment {
        lhs: Identifier,
        expr: Expression,
    },
    WhileLoop {
        condition: Expression,
        body: Block,
    },
    Expression {
        expr: Expression,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Pattern {
    Identifier(Identifier),
}

#[derive(Debug, PartialEq, Clone)]
pub enum TypeDefinition {
    Name {
        name: Identifier,
    },
    Array {
        type_def: Box<TypeDefinition>,
        size: Option<Expression>,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    ByteLiteral(String),
    Identifier(Identifier),
    Number(Number),
    Call {
        method: Box<Expression>,
        args: CallArgs,
    },
    Access {
        target: Box<Expression>,
        field: Box<Expression>,
    },
    Branch {
        /// Condition to be executed to determine which block
        /// is run
        condition: Box<Expression>,
        /// executed if the condition is non-zero
        body: Block,
        /// (optional) executed if the condition is zero
        otherwise: Option<Block>,
    },
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Identifier(Vec<String>);

impl Identifier {
    // NOTE: Do not implement ::new() for Identifier
    // Having an empty Identifier does not make any sense!

    // Concatenates this identifier with another identifier and returns
    // a new identifier
    pub fn concat<T>(self, other: T) -> Identifier where T: IntoIterator<Item=String> {
        self.into_iter().chain(other).collect()
    }
}

impl FromStr for Identifier {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Identifier(s.split("::").map(|s| s.to_owned()).collect()))
    }
}

impl<'a> From<&'a str> for Identifier {
    fn from(s: &'a str) -> Identifier {
        s.parse().unwrap()
    }
}

impl IntoIterator for Identifier {
    type Item = String;
    type IntoIter = ::std::vec::IntoIter<String>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromIterator<String> for Identifier {
    fn from_iter<I: IntoIterator<Item=String>>(iter: I) -> Self {
        Identifier(iter.into_iter().collect())
    }
}

pub type Block = Vec<Statement>;
pub type Number = i32;
pub type CallArgs = Vec<CallArg>;
pub type CallArg = Expression;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn concat_identifiers() {
        let ident = Identifier::from("foo::bar::Bar::spam")
            .concat(Identifier::from("car::bar::star"));

        let concated = Identifier::from("foo::bar::Bar::spam::car::bar::star");

        assert_eq!(ident, concated);
    }
}
<|endoftext|>