<commit_before>//! HTTP/HTTPS URL type for Iron.

use url::{self, Host};
use std::fmt;

/// HTTP/HTTPS URL type for Iron.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Url {
    /// The generic rust-url that corresponds to this Url
    generic_url: url::Url,
}

impl Url {
    /// Create a URL from a string.
    ///
    /// The input must be a valid URL with a special scheme for this to succeed.
    ///
    /// HTTP and HTTPS are special schemes.
    ///
    /// See: http://url.spec.whatwg.org/#special-scheme
    pub fn parse(input: &str) -> Result<Url, String> {
        // Parse the string using rust-url, then convert.
        match url::Url::parse(input) {
            Ok(raw_url) => Url::from_generic_url(raw_url),
            Err(e) => Err(format!("{}", e))
        }
    }

    /// Create a `Url` from a `rust-url` `Url`.
    pub fn from_generic_url(raw_url: url::Url) -> Result<Url, String> {
        // Create an Iron URL by verifying the `rust-url` `Url` is a special
        // scheme that Iron supports.
        if raw_url.cannot_be_a_base() {
            Err(format!("Not a special scheme: `{}`", raw_url.scheme()))
        } else if raw_url.port_or_known_default().is_none() {
            Err(format!("Invalid special scheme: `{}`", raw_url.scheme()))
        } else {
            Ok(Url {
                generic_url: raw_url,
            })
        }
    }

    /// Create a `rust-url` `Url` from a `Url`.
    pub fn into_generic_url(self) -> url::Url {
        self.generic_url
    }

    /// Return an immutable pointer to the underlying `rust-url` `Url`.
    pub fn generic_url(&self) -> &url::Url {
        &self.generic_url
    }

    /// Return a mutable pointer to the underlying `rust-url` `Url`.
    pub fn generic_url_mut(&mut self) -> &mut url::Url {
        &mut self.generic_url
    }

    /// The lower-cased scheme of the URL, typically "http" or "https".
    pub fn scheme(&self) -> &str {
        self.generic_url.scheme()
    }

    /// The host field of the URL, probably a domain.
    pub fn host(&self) -> Host<&str> {
        // `unwrap` is safe here because urls that cannot be a base don't have a host
        self.generic_url.host().unwrap()
    }

    /// The connection port.
    pub fn port(&self) -> u16 {
        // `unwrap` is safe here because we checked `port_or_known_default`
        // in `from_generic_url`.
        self.generic_url.port_or_known_default().unwrap()
    }

    /// The URL path, the resource to be accessed.
    ///
    /// A *non-empty* vector encoding the parts of the URL path.
    /// Empty entries of `""` correspond to trailing slashes.
    pub fn path(&self) -> Vec<&str> {
        // `unwrap` is safe here because urls that can be a base will have `Some`.
        self.generic_url.path_segments().unwrap().collect()
    }

    /// The URL username field, from the userinfo section of the URL.
    ///
    /// `None` if the `@` character was not part of the input OR
    /// if a blank username was provided.
    /// Otherwise, a non-empty string.
    pub fn username(&self) -> Option<&str> {
        // Map empty usernames to None.
        match self.generic_url.username() {
            "" => None,
            username => Some(username)
        }
    }

    /// The URL password field, from the userinfo section of the URL.
    ///
    /// `None` if the `@` character was not part of the input OR
    /// if a blank password was provided.
    /// Otherwise, a non-empty string.
    pub fn password(&self) -> Option<&str> {
        // Map empty passwords to None.
        match self.generic_url.password() {
            None => None,
            Some(ref x) if x.is_empty() => None,
            Some(password) => Some(password)
        }
    }

    /// The URL query string.
    ///
    /// `None` if the `?` character was not part of the input.
    /// Otherwise, a possibly empty, percent encoded string.
    pub fn query(&self) -> Option<&str> {
        self.generic_url.query()
    }

    /// The URL fragment.
    ///
    /// `None` if the `#` character was not part of the input.
    /// Otherwise, a possibly empty, percent encoded string.
    pub fn fragment(&self) -> Option<&str> {
        self.generic_url.fragment()
    }
}

impl fmt::Display for Url {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        try!(self.generic_url.fmt(formatter));
        Ok(())
    }
}

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

    #[test]
    fn test_default_port() {
        assert_eq!(Url::parse("http://example.com/wow").unwrap().port(), 80u16);
        assert_eq!(Url::parse("https://example.com/wow").unwrap().port(), 443u16);
    }

    #[test]
    fn test_explicit_port() {
        assert_eq!(Url::parse("http://localhost:3097").unwrap().port(), 3097u16);
    }

    #[test]
    fn test_empty_username() {
        assert!(Url::parse("http://@example.com").unwrap().username().is_none());
        assert!(Url::parse("http://:password@example.com").unwrap().username().is_none());
    }

    #[test]
    fn test_not_empty_username() {
        let url = Url::parse("http://john:pass@example.com").unwrap();
        assert_eq!(url.username().unwrap(), "john");

        let url = Url::parse("http://john:@example.com").unwrap();
        assert_eq!(url.username().unwrap(), "john");
    }

    #[test]
    fn test_empty_password() {
        assert!(Url::parse("http://michael@example.com").unwrap().password().is_none());
        assert!(Url::parse("http://:@example.com").unwrap().password().is_none());
    }

    #[test]
    fn test_not_empty_password() {
        let url = Url::parse("http://michael:pass@example.com").unwrap();
        assert_eq!(url.password().unwrap(), "pass");

        let url = Url::parse("http://:pass@example.com").unwrap();
        assert_eq!(url.password().unwrap(), "pass");
    }

    #[test]
    fn test_formatting() {
        assert_eq!(Url::parse("http://michael@example.com/path/?q=wow").unwrap().to_string(),
                    "http://michael@example.com/path/?q=wow".to_string());
    }

    #[test]
    fn test_conversion() {
        let url_str = "https://user:password@iron.com:8080/path?q=wow#fragment";
        let url = Url::parse(url_str).unwrap();

        // Convert to a generic URL and check fidelity.
        let raw_url = url.clone().into_generic_url();
        assert_eq!(::url::Url::parse(url_str).unwrap(), raw_url);

        // Convert back to an Iron URL and check fidelity.
        let new_url = Url::from_generic_url(raw_url).unwrap();
        assert_eq!(url, new_url);
    }

    #[test]
    fn test_https_non_default_port() {
        let parsed = Url::parse("https://example.com:8080").unwrap().to_string();
        assert_eq!(parsed, "https://example.com:8080/");
    }

    #[test]
    fn test_https_default_port() {
        let parsed = Url::parse("https://example.com:443").unwrap().to_string();
        assert_eq!(parsed, "https://example.com/");
    }
}
<commit_msg>Implement traits to convert to url::Url<commit_after>//! HTTP/HTTPS URL type for Iron.

use url::{self, Host};
use std::fmt;

/// HTTP/HTTPS URL type for Iron.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Url {
    /// The generic rust-url that corresponds to this Url
    generic_url: url::Url,
}

impl Url {
    /// Create a URL from a string.
    ///
    /// The input must be a valid URL with a special scheme for this to succeed.
    ///
    /// HTTP and HTTPS are special schemes.
    ///
    /// See: http://url.spec.whatwg.org/#special-scheme
    pub fn parse(input: &str) -> Result<Url, String> {
        // Parse the string using rust-url, then convert.
        match url::Url::parse(input) {
            Ok(raw_url) => Url::from_generic_url(raw_url),
            Err(e) => Err(format!("{}", e))
        }
    }

    /// Create a `Url` from a `rust-url` `Url`.
    pub fn from_generic_url(raw_url: url::Url) -> Result<Url, String> {
        // Create an Iron URL by verifying the `rust-url` `Url` is a special
        // scheme that Iron supports.
        if raw_url.cannot_be_a_base() {
            Err(format!("Not a special scheme: `{}`", raw_url.scheme()))
        } else if raw_url.port_or_known_default().is_none() {
            Err(format!("Invalid special scheme: `{}`", raw_url.scheme()))
        } else {
            Ok(Url {
                generic_url: raw_url,
            })
        }
    }

    /// Create a `rust-url` `Url` from a `Url`.
    #[deprecated(since="0.5.0", note="use `into` from the `Into` trait instead")]
    pub fn into_generic_url(self) -> url::Url {
        self.generic_url
    }

    /// The lower-cased scheme of the URL, typically "http" or "https".
    pub fn scheme(&self) -> &str {
        self.generic_url.scheme()
    }

    /// The host field of the URL, probably a domain.
    pub fn host(&self) -> Host<&str> {
        // `unwrap` is safe here because urls that cannot be a base don't have a host
        self.generic_url.host().unwrap()
    }

    /// The connection port.
    pub fn port(&self) -> u16 {
        // `unwrap` is safe here because we checked `port_or_known_default`
        // in `from_generic_url`.
        self.generic_url.port_or_known_default().unwrap()
    }

    /// The URL path, the resource to be accessed.
    ///
    /// A *non-empty* vector encoding the parts of the URL path.
    /// Empty entries of `""` correspond to trailing slashes.
    pub fn path(&self) -> Vec<&str> {
        // `unwrap` is safe here because urls that can be a base will have `Some`.
        self.generic_url.path_segments().unwrap().collect()
    }

    /// The URL username field, from the userinfo section of the URL.
    ///
    /// `None` if the `@` character was not part of the input OR
    /// if a blank username was provided.
    /// Otherwise, a non-empty string.
    pub fn username(&self) -> Option<&str> {
        // Map empty usernames to None.
        match self.generic_url.username() {
            "" => None,
            username => Some(username)
        }
    }

    /// The URL password field, from the userinfo section of the URL.
    ///
    /// `None` if the `@` character was not part of the input OR
    /// if a blank password was provided.
    /// Otherwise, a non-empty string.
    pub fn password(&self) -> Option<&str> {
        // Map empty passwords to None.
        match self.generic_url.password() {
            None => None,
            Some(ref x) if x.is_empty() => None,
            Some(password) => Some(password)
        }
    }

    /// The URL query string.
    ///
    /// `None` if the `?` character was not part of the input.
    /// Otherwise, a possibly empty, percent encoded string.
    pub fn query(&self) -> Option<&str> {
        self.generic_url.query()
    }

    /// The URL fragment.
    ///
    /// `None` if the `#` character was not part of the input.
    /// Otherwise, a possibly empty, percent encoded string.
    pub fn fragment(&self) -> Option<&str> {
        self.generic_url.fragment()
    }
}

impl fmt::Display for Url {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        try!(self.generic_url.fmt(formatter));
        Ok(())
    }
}

impl Into<url::Url> for Url {
    fn into(self) -> url::Url { self.generic_url }
}

impl AsRef<url::Url> for Url {
    fn as_ref(&self) -> &url::Url { &self.generic_url }
}

impl AsMut<url::Url> for Url {
    fn as_mut(&mut self) -> &mut url::Url { &mut self.generic_url }
}

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

    #[test]
    fn test_default_port() {
        assert_eq!(Url::parse("http://example.com/wow").unwrap().port(), 80u16);
        assert_eq!(Url::parse("https://example.com/wow").unwrap().port(), 443u16);
    }

    #[test]
    fn test_explicit_port() {
        assert_eq!(Url::parse("http://localhost:3097").unwrap().port(), 3097u16);
    }

    #[test]
    fn test_empty_username() {
        assert!(Url::parse("http://@example.com").unwrap().username().is_none());
        assert!(Url::parse("http://:password@example.com").unwrap().username().is_none());
    }

    #[test]
    fn test_not_empty_username() {
        let url = Url::parse("http://john:pass@example.com").unwrap();
        assert_eq!(url.username().unwrap(), "john");

        let url = Url::parse("http://john:@example.com").unwrap();
        assert_eq!(url.username().unwrap(), "john");
    }

    #[test]
    fn test_empty_password() {
        assert!(Url::parse("http://michael@example.com").unwrap().password().is_none());
        assert!(Url::parse("http://:@example.com").unwrap().password().is_none());
    }

    #[test]
    fn test_not_empty_password() {
        let url = Url::parse("http://michael:pass@example.com").unwrap();
        assert_eq!(url.password().unwrap(), "pass");

        let url = Url::parse("http://:pass@example.com").unwrap();
        assert_eq!(url.password().unwrap(), "pass");
    }

    #[test]
    fn test_formatting() {
        assert_eq!(Url::parse("http://michael@example.com/path/?q=wow").unwrap().to_string(),
                    "http://michael@example.com/path/?q=wow".to_string());
    }

    #[test]
    fn test_conversion() {
        let url_str = "https://user:password@iron.com:8080/path?q=wow#fragment";
        let url = Url::parse(url_str).unwrap();

        // Convert to a generic URL and check fidelity.
        let raw_url: ::url::Url = url.clone().into();
        assert_eq!(::url::Url::parse(url_str).unwrap(), raw_url);

        // Convert back to an Iron URL and check fidelity.
        let new_url = Url::from_generic_url(raw_url).unwrap();
        assert_eq!(url, new_url);
    }

    #[test]
    fn test_https_non_default_port() {
        let parsed = Url::parse("https://example.com:8080").unwrap().to_string();
        assert_eq!(parsed, "https://example.com:8080/");
    }

    #[test]
    fn test_https_default_port() {
        let parsed = Url::parse("https://example.com:443").unwrap().to_string();
        assert_eq!(parsed, "https://example.com/");
    }
}
<|endoftext|>


<commit_before>use libc;
use fcntl::Fd;
use {Error, Result};

bitflags!(
    flags EventFdFlag: libc::c_int {
        const EFD_CLOEXEC   = 0o2000000, // Since Linux 2.6.27
        const EFD_NONBLOCK  = 0o0004000, // Since Linux 2.6.27
        const EFD_SEMAPHORE = 0o0000001, // Since Linux 2.6.30
    }
);

mod ffi {
    use libc;

    extern {
        pub fn eventfd(initval: libc::c_uint, flags: libc::c_int) -> libc::c_int;
    }
}

pub fn eventfd(initval: usize, flags: EventFdFlag) -> Result<Fd> {
    unsafe {
        let res = ffi::eventfd(initval as libc::c_uint, flags.bits());

        if res < 0 {
            return Err(Error::last());
        }

        Ok(res as Fd)
    }
}
<commit_msg>Make eventfds compile again<commit_after>use libc;
use std::os::unix::io::RawFd;
use {Error, Result};

bitflags!(
    flags EventFdFlag: libc::c_int {
        const EFD_CLOEXEC   = 0o2000000, // Since Linux 2.6.27
        const EFD_NONBLOCK  = 0o0004000, // Since Linux 2.6.27
        const EFD_SEMAPHORE = 0o0000001, // Since Linux 2.6.30
    }
);

mod ffi {
    use libc;

    extern {
        pub fn eventfd(initval: libc::c_uint, flags: libc::c_int) -> libc::c_int;
    }
}

pub fn eventfd(initval: usize, flags: EventFdFlag) -> Result<RawFd> {
    unsafe {
        let res = ffi::eventfd(initval as libc::c_uint, flags.bits());

        if res < 0 {
            return Err(Error::last());
        }

        Ok(res as RawFd)
    }
}
<|endoftext|>


<commit_before>use uuid::Uuid;

pub fn uuid_to_label(id: &Uuid) -> String {
    id.simple().to_string()
}

pub fn label_to_uuid(id: &str) -> Result<Uuid, String> {
    match Uuid::parse_str(id) {
        Ok(id) => Ok(id),
        Err(_) => Err("Invalid uuid form".to_owned())
    }
}
<commit_msg>fix: Update uuid API change<commit_after>use uuid::Uuid;

pub fn uuid_to_label(id: &Uuid) -> String {
    id.to_simple().to_string()
}

pub fn label_to_uuid(id: &str) -> Result<Uuid, String> {
    match Uuid::parse_str(id) {
        Ok(id) => Ok(id),
        Err(_) => Err("Invalid uuid form".to_owned())
    }
}
<|endoftext|>


<commit_before>use fastup::{Document, Node, parse};
use fastup::Node::{Text, Foreground, Background, Bold};

/// Expand widgets to nodes until there are no widgets in the node tree
/// any more.
///
/// It is guranteed that all `Node`s in the returned `Document`
/// contains no `Node::Widget(..)`.
pub fn expand(doc: Document) -> Document {
    Document(doc.0.into_iter().map(expand_node).collect())
}

fn expand_node(node: Node) -> Node {
    match node {
        Text(..) => node,
        Foreground(color, doc) => Foreground(color, expand(doc)),
        Background(color, doc) => Background(color, expand(doc)),
        Bold(doc) => Bold(expand(doc)),
        Node::Widget(..) => {
            expand_node(error_node("unimplemented"))
        }
    }
}

/// Create a `Node` as formatted error message `err`.
/// The `err` should be a valid fastup markup text.
pub fn error_node(err: &str) -> Node {
    parse(&format!("[ff0000: (ffffff: {{\\<ERROR: {}\\>}})]", err))
        .unwrap()
        .0
        .into_iter()
        .next()
        .unwrap()
}

factory! {
    pub trait Widget {
        fn expand(&self, args: Vec<String>) -> Node;
    }

    /// Create a widget by `name`.
    make {
    }
}

<commit_msg>widget expanding is implemented.<commit_after>use fastup::{Document, Node, parse};
use fastup::Node::{Text, Foreground, Background, Bold};

/// Expand widgets to nodes until there are no widgets in the node tree
/// any more.
///
/// It is guranteed that all `Node`s in the returned `Document`
/// contains no `Node::Widget(..)`.
pub fn expand(doc: Document) -> Document {
    Document(doc.0.into_iter().map(expand_node).collect())
}

fn expand_node(node: Node) -> Node {
    match node {
        Text(..) => node,
        Foreground(color, doc) => Foreground(color, expand(doc)),
        Background(color, doc) => Background(color, expand(doc)),
        Bold(doc) => Bold(expand(doc)),
        Node::Widget(name, args) => {
            let node = make(&name)
                .map(|widget| widget.expand(args))
                .unwrap_or_else(|| no_widget_error_node(&name));
            expand_node(node)
        }
    }
}

fn no_widget_error_node(widget_name: &str) -> Node {
    let err = format!("no such widget: (ccdd44: {})", widget_name);
    error_node(&err)
}

/// Create a `Node` as formatted error message `err`.
/// The `err` should be a valid fastup markup text.
pub fn error_node(err: &str) -> Node {
    parse(&format!("[551100: (ff6666: \\ (44ccdd:\\<)ERROR: {}(44ccdd:\\>) )]", err))
        .unwrap()
        .0
        .into_iter()
        .next()
        .unwrap()
}

factory! {
    pub trait Widget {
        fn expand(&self, args: Vec<String>) -> Node;
    }

    /// Create a widget by `name`.
    make {
    }
}

<|endoftext|>


<commit_before>//! This modules implements a function to resolve a path `foo::bar::baz` to a
//! def, which is used within the name resolution.
//!
//! When name resolution is finished, the result of resolving a path is either
//! `Some(def)` or `None`. However, when we are in process of resolving imports
//! or macros, there's a third possibility:
//!
//!   I can't resolve this path right now, but I might be resolve this path
//!   later, when more macros are expanded.
//!
//! `ReachedFixedPoint` signals about this.

use hir_expand::name::Name;
use ra_db::Edition;
use test_utils::tested_by;

use crate::{
    db::DefDatabase,
    nameres::{BuiltinShadowMode, CrateDefMap},
    path::{Path, PathKind},
    per_ns::PerNs,
    AdtId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum ResolveMode {
    Import,
    Other,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum ReachedFixedPoint {
    Yes,
    No,
}

#[derive(Debug, Clone)]
pub(super) struct ResolvePathResult {
    pub(super) resolved_def: PerNs,
    pub(super) segment_index: Option<usize>,
    pub(super) reached_fixedpoint: ReachedFixedPoint,
}

impl ResolvePathResult {
    fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
        ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
    }

    fn with(
        resolved_def: PerNs,
        reached_fixedpoint: ReachedFixedPoint,
        segment_index: Option<usize>,
    ) -> ResolvePathResult {
        ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
    }
}

impl CrateDefMap {
    pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
        self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
    }

    // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
    // the result.
    pub(super) fn resolve_path_fp_with_macro(
        &self,
        db: &impl DefDatabase,
        mode: ResolveMode,
        original_module: LocalModuleId,
        path: &Path,
        shadow: BuiltinShadowMode,
    ) -> ResolvePathResult {
        let mut segments = path.segments.iter().enumerate().peekable();

        let mut curr_per_ns: PerNs = match path.kind {
            PathKind::DollarCrate(krate) => {
                if krate == self.krate {
                    tested_by!(macro_dollar_crate_self);
                    PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into())
                } else {
                    let def_map = db.crate_def_map(krate);
                    let module = ModuleId { krate, local_id: def_map.root };
                    tested_by!(macro_dollar_crate_other);
                    PerNs::types(module.into())
                }
            }
            PathKind::Crate => {
                PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into())
            }
            PathKind::Self_ => {
                PerNs::types(ModuleId { krate: self.krate, local_id: original_module }.into())
            }
            // plain import or absolute path in 2015: crate-relative with
            // fallback to extern prelude (with the simplification in
            // rust-lang/rust#57745)
            // FIXME there must be a nicer way to write this condition
            PathKind::Plain | PathKind::Abs
                if self.edition == Edition::Edition2015
                    && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
            {
                let segment = match segments.next() {
                    Some((_, segment)) => segment,
                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                };
                log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);

                self.resolve_name_in_crate_root_or_extern_prelude(
                    &segment.name,
                    prefer_module(&mut segments, shadow),
                )
            }
            PathKind::Plain => {
                let segment = match segments.next() {
                    Some((_, segment)) => segment,
                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                };
                log::debug!("resolving {:?} in module", segment);
                self.resolve_name_in_module(
                    db,
                    original_module,
                    &segment.name,
                    prefer_module(&mut segments, shadow),
                )
            }
            PathKind::Super => {
                if let Some(p) = self.modules[original_module].parent {
                    PerNs::types(ModuleId { krate: self.krate, local_id: p }.into())
                } else {
                    log::debug!("super path in root module");
                    return ResolvePathResult::empty(ReachedFixedPoint::Yes);
                }
            }
            PathKind::Abs => {
                // 2018-style absolute path -- only extern prelude
                let segment = match segments.next() {
                    Some((_, segment)) => segment,
                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                };
                if let Some(def) = self.extern_prelude.get(&segment.name) {
                    log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
                    PerNs::types(*def)
                } else {
                    return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
                }
            }
            PathKind::Type(_) => {
                // This is handled in `infer::infer_path_expr`
                // The result returned here does not matter
                return ResolvePathResult::empty(ReachedFixedPoint::Yes);
            }
        };

        while let Some((i, segment)) = segments.next() {
            let curr = match curr_per_ns.take_types() {
                Some(r) => r,
                None => {
                    // we still have path segments left, but the path so far
                    // didn't resolve in the types namespace => no resolution
                    // (don't break here because `curr_per_ns` might contain
                    // something in the value namespace, and it would be wrong
                    // to return that)
                    return ResolvePathResult::empty(ReachedFixedPoint::No);
                }
            };
            // resolve segment in curr

            curr_per_ns = match curr {
                ModuleDefId::ModuleId(module) => {
                    if module.krate != self.krate {
                        let path =
                            Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
                        log::debug!("resolving {:?} in other crate", path);
                        let defp_map = db.crate_def_map(module.krate);
                        let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
                        return ResolvePathResult::with(
                            def,
                            ReachedFixedPoint::Yes,
                            s.map(|s| s + i),
                        );
                    }

                    // Since it is a qualified path here, it should not contains legacy macros
                    match self[module.local_id]
                        .scope
                        .get(&segment.name, prefer_module(&mut segments, shadow))
                    {
                        Some(res) => res.def,
                        _ => {
                            log::debug!("path segment {:?} not found", segment.name);
                            return ResolvePathResult::empty(ReachedFixedPoint::No);
                        }
                    }
                }
                ModuleDefId::AdtId(AdtId::EnumId(e)) => {
                    // enum variant
                    tested_by!(can_import_enum_variant);
                    let enum_data = db.enum_data(e);
                    match enum_data.variant(&segment.name) {
                        Some(local_id) => {
                            let variant = EnumVariantId { parent: e, local_id };
                            PerNs::both(variant.into(), variant.into())
                        }
                        None => {
                            return ResolvePathResult::with(
                                PerNs::types(e.into()),
                                ReachedFixedPoint::Yes,
                                Some(i),
                            );
                        }
                    }
                }
                s => {
                    // could be an inherent method call in UFCS form
                    // (`Struct::method`), or some other kind of associated item
                    log::debug!(
                        "path segment {:?} resolved to non-module {:?}, but is not last",
                        segment.name,
                        curr,
                    );

                    return ResolvePathResult::with(
                        PerNs::types(s),
                        ReachedFixedPoint::Yes,
                        Some(i),
                    );
                }
            };
        }
        return ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None);

        // if it is not the last segment, we prefer builtin as module
        fn prefer_module<I>(
            segments: &mut std::iter::Peekable<I>,
            shadow: BuiltinShadowMode,
        ) -> BuiltinShadowMode
        where
            I: Iterator,
        {
            if segments.peek().is_some() {
                BuiltinShadowMode::Module
            } else {
                shadow
            }
        }
    }

    fn resolve_name_in_module(
        &self,
        db: &impl DefDatabase,
        module: LocalModuleId,
        name: &Name,
        shadow: BuiltinShadowMode,
    ) -> PerNs {
        // Resolve in:
        //  - legacy scope of macro
        //  - current module / scope
        //  - extern prelude
        //  - std prelude
        let from_legacy_macro =
            self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
        let from_scope =
            self[module].scope.get(name, shadow).map_or_else(PerNs::none, |res| res.def);
        let from_extern_prelude =
            self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
        let from_prelude = self.resolve_in_prelude(db, name, shadow);

        from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
    }

    fn resolve_name_in_crate_root_or_extern_prelude(
        &self,
        name: &Name,
        shadow: BuiltinShadowMode,
    ) -> PerNs {
        let from_crate_root =
            self[self.root].scope.get(name, shadow).map_or_else(PerNs::none, |res| res.def);
        let from_extern_prelude = self.resolve_name_in_extern_prelude(name);

        from_crate_root.or(from_extern_prelude)
    }

    fn resolve_in_prelude(
        &self,
        db: &impl DefDatabase,
        name: &Name,
        shadow: BuiltinShadowMode,
    ) -> PerNs {
        if let Some(prelude) = self.prelude {
            let keep;
            let def_map = if prelude.krate == self.krate {
                self
            } else {
                // Extend lifetime
                keep = db.crate_def_map(prelude.krate);
                &keep
            };
            def_map[prelude.local_id]
                .scope
                .get(name, shadow)
                .map_or_else(PerNs::none, |res| res.def)
        } else {
            PerNs::none()
        }
    }
}
<commit_msg>Use index instead of peekable<commit_after>//! This modules implements a function to resolve a path `foo::bar::baz` to a
//! def, which is used within the name resolution.
//!
//! When name resolution is finished, the result of resolving a path is either
//! `Some(def)` or `None`. However, when we are in process of resolving imports
//! or macros, there's a third possibility:
//!
//!   I can't resolve this path right now, but I might be resolve this path
//!   later, when more macros are expanded.
//!
//! `ReachedFixedPoint` signals about this.

use hir_expand::name::Name;
use ra_db::Edition;
use test_utils::tested_by;

use crate::{
    db::DefDatabase,
    nameres::{BuiltinShadowMode, CrateDefMap},
    path::{Path, PathKind},
    per_ns::PerNs,
    AdtId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum ResolveMode {
    Import,
    Other,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum ReachedFixedPoint {
    Yes,
    No,
}

#[derive(Debug, Clone)]
pub(super) struct ResolvePathResult {
    pub(super) resolved_def: PerNs,
    pub(super) segment_index: Option<usize>,
    pub(super) reached_fixedpoint: ReachedFixedPoint,
}

impl ResolvePathResult {
    fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
        ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
    }

    fn with(
        resolved_def: PerNs,
        reached_fixedpoint: ReachedFixedPoint,
        segment_index: Option<usize>,
    ) -> ResolvePathResult {
        ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
    }
}

impl CrateDefMap {
    pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
        self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
    }

    // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
    // the result.
    pub(super) fn resolve_path_fp_with_macro(
        &self,
        db: &impl DefDatabase,
        mode: ResolveMode,
        original_module: LocalModuleId,
        path: &Path,
        shadow: BuiltinShadowMode,
    ) -> ResolvePathResult {
        // if it is not the last segment, we prefer the module to the builtin
        let prefer_module = |index| {
            if index == path.segments.len() - 1 {
                shadow
            } else {
                BuiltinShadowMode::Module
            }
        };

        let mut segments = path.segments.iter().enumerate();

        let mut curr_per_ns: PerNs = match path.kind {
            PathKind::DollarCrate(krate) => {
                if krate == self.krate {
                    tested_by!(macro_dollar_crate_self);
                    PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into())
                } else {
                    let def_map = db.crate_def_map(krate);
                    let module = ModuleId { krate, local_id: def_map.root };
                    tested_by!(macro_dollar_crate_other);
                    PerNs::types(module.into())
                }
            }
            PathKind::Crate => {
                PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into())
            }
            PathKind::Self_ => {
                PerNs::types(ModuleId { krate: self.krate, local_id: original_module }.into())
            }
            // plain import or absolute path in 2015: crate-relative with
            // fallback to extern prelude (with the simplification in
            // rust-lang/rust#57745)
            // FIXME there must be a nicer way to write this condition
            PathKind::Plain | PathKind::Abs
                if self.edition == Edition::Edition2015
                    && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
            {
                let (idx, segment) = match segments.next() {
                    Some((idx, segment)) => (idx, segment),
                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                };
                log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);

                self.resolve_name_in_crate_root_or_extern_prelude(&segment.name, prefer_module(idx))
            }
            PathKind::Plain => {
                let (idx, segment) = match segments.next() {
                    Some((idx, segment)) => (idx, segment),
                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                };
                log::debug!("resolving {:?} in module", segment);
                self.resolve_name_in_module(db, original_module, &segment.name, prefer_module(idx))
            }
            PathKind::Super => {
                if let Some(p) = self.modules[original_module].parent {
                    PerNs::types(ModuleId { krate: self.krate, local_id: p }.into())
                } else {
                    log::debug!("super path in root module");
                    return ResolvePathResult::empty(ReachedFixedPoint::Yes);
                }
            }
            PathKind::Abs => {
                // 2018-style absolute path -- only extern prelude
                let segment = match segments.next() {
                    Some((_, segment)) => segment,
                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                };
                if let Some(def) = self.extern_prelude.get(&segment.name) {
                    log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
                    PerNs::types(*def)
                } else {
                    return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
                }
            }
            PathKind::Type(_) => {
                // This is handled in `infer::infer_path_expr`
                // The result returned here does not matter
                return ResolvePathResult::empty(ReachedFixedPoint::Yes);
            }
        };

        for (i, segment) in segments {
            let curr = match curr_per_ns.take_types() {
                Some(r) => r,
                None => {
                    // we still have path segments left, but the path so far
                    // didn't resolve in the types namespace => no resolution
                    // (don't break here because `curr_per_ns` might contain
                    // something in the value namespace, and it would be wrong
                    // to return that)
                    return ResolvePathResult::empty(ReachedFixedPoint::No);
                }
            };
            // resolve segment in curr

            curr_per_ns = match curr {
                ModuleDefId::ModuleId(module) => {
                    if module.krate != self.krate {
                        let path =
                            Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
                        log::debug!("resolving {:?} in other crate", path);
                        let defp_map = db.crate_def_map(module.krate);
                        let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
                        return ResolvePathResult::with(
                            def,
                            ReachedFixedPoint::Yes,
                            s.map(|s| s + i),
                        );
                    }

                    // Since it is a qualified path here, it should not contains legacy macros
                    match self[module.local_id].scope.get(&segment.name, prefer_module(i)) {
                        Some(res) => res.def,
                        _ => {
                            log::debug!("path segment {:?} not found", segment.name);
                            return ResolvePathResult::empty(ReachedFixedPoint::No);
                        }
                    }
                }
                ModuleDefId::AdtId(AdtId::EnumId(e)) => {
                    // enum variant
                    tested_by!(can_import_enum_variant);
                    let enum_data = db.enum_data(e);
                    match enum_data.variant(&segment.name) {
                        Some(local_id) => {
                            let variant = EnumVariantId { parent: e, local_id };
                            PerNs::both(variant.into(), variant.into())
                        }
                        None => {
                            return ResolvePathResult::with(
                                PerNs::types(e.into()),
                                ReachedFixedPoint::Yes,
                                Some(i),
                            );
                        }
                    }
                }
                s => {
                    // could be an inherent method call in UFCS form
                    // (`Struct::method`), or some other kind of associated item
                    log::debug!(
                        "path segment {:?} resolved to non-module {:?}, but is not last",
                        segment.name,
                        curr,
                    );

                    return ResolvePathResult::with(
                        PerNs::types(s),
                        ReachedFixedPoint::Yes,
                        Some(i),
                    );
                }
            };
        }

        ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
    }

    fn resolve_name_in_module(
        &self,
        db: &impl DefDatabase,
        module: LocalModuleId,
        name: &Name,
        shadow: BuiltinShadowMode,
    ) -> PerNs {
        // Resolve in:
        //  - legacy scope of macro
        //  - current module / scope
        //  - extern prelude
        //  - std prelude
        let from_legacy_macro =
            self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
        let from_scope =
            self[module].scope.get(name, shadow).map_or_else(PerNs::none, |res| res.def);
        let from_extern_prelude =
            self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
        let from_prelude = self.resolve_in_prelude(db, name, shadow);

        from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
    }

    fn resolve_name_in_crate_root_or_extern_prelude(
        &self,
        name: &Name,
        shadow: BuiltinShadowMode,
    ) -> PerNs {
        let from_crate_root =
            self[self.root].scope.get(name, shadow).map_or_else(PerNs::none, |res| res.def);
        let from_extern_prelude = self.resolve_name_in_extern_prelude(name);

        from_crate_root.or(from_extern_prelude)
    }

    fn resolve_in_prelude(
        &self,
        db: &impl DefDatabase,
        name: &Name,
        shadow: BuiltinShadowMode,
    ) -> PerNs {
        if let Some(prelude) = self.prelude {
            let keep;
            let def_map = if prelude.krate == self.krate {
                self
            } else {
                // Extend lifetime
                keep = db.crate_def_map(prelude.krate);
                &keep
            };
            def_map[prelude.local_id]
                .scope
                .get(name, shadow)
                .map_or_else(PerNs::none, |res| res.def)
        } else {
            PerNs::none()
        }
    }
}
<|endoftext|>


<commit_before>use super::*;

// test expr_literals
// fn foo() {
//     let _ = true;
//     let _ = false;
//     let _ = 1;
//     let _ = 2.0;
//     let _ = b'a';
//     let _ = 'b';
//     let _ = "c";
//     let _ = r"d";
//     let _ = b"e";
//     let _ = br"f";
// }
pub(crate) const LITERAL_FIRST: TokenSet = token_set![
    TRUE_KW,
    FALSE_KW,
    INT_NUMBER,
    FLOAT_NUMBER,
    BYTE,
    CHAR,
    STRING,
    RAW_STRING,
    BYTE_STRING,
    RAW_BYTE_STRING
];

pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
    if !p.at_ts(LITERAL_FIRST) {
        return None;
    }
    let m = p.start();
    p.bump();
    Some(m.complete(p, LITERAL))
}

// E.g. for after the break in `if break {}`, this should not match
pub(super) const ATOM_EXPR_FIRST: TokenSet = LITERAL_FIRST.union(token_set![
    L_PAREN,
    L_CURLY,
    L_BRACK,
    L_ANGLE, // Universal function call syntax
    PIPE,
    MOVE_KW,
    IF_KW,
    WHILE_KW,
    MATCH_KW,
    UNSAFE_KW,
    RETURN_KW,
    IDENT,
    SELF_KW,
    SUPER_KW,
    CRATE_KW,
    COLONCOLON,
    BREAK_KW,
    CONTINUE_KW,
    LIFETIME,
]);

const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW];

pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
    if let Some(m) = literal(p) {
        return Some((m, BlockLike::NotBlock));
    }
    if paths::is_path_start(p) || p.at(L_ANGLE) {
        return Some(path_expr(p, r));
    }
    let la = p.nth(1);
    let done = match p.current() {
        L_PAREN => tuple_expr(p),
        L_BRACK => array_expr(p),
        PIPE => lambda_expr(p),
        MOVE_KW if la == PIPE => lambda_expr(p),
        IF_KW => if_expr(p),

        LOOP_KW => loop_expr(p, None),
        FOR_KW => for_expr(p, None),
        WHILE_KW => while_expr(p, None),
        LIFETIME if la == COLON => {
            let m = p.start();
            label(p);
            match p.current() {
                LOOP_KW => loop_expr(p, Some(m)),
                FOR_KW => for_expr(p, Some(m)),
                WHILE_KW => while_expr(p, Some(m)),
                L_CURLY => block_expr(p, Some(m)),
                _ => {
                    // test_err misplaced_label_err
                    // fn main() {
                    //     'loop: impl
                    // }
                    p.error("expected a loop");
                    m.complete(p, ERROR);
                    return None;
                }
            }
        }

        MATCH_KW => match_expr(p),
        UNSAFE_KW if la == L_CURLY => {
            let m = p.start();
            p.bump();
            block_expr(p, Some(m))
        }
        L_CURLY => block_expr(p, None),
        RETURN_KW => return_expr(p),
        CONTINUE_KW => continue_expr(p),
        BREAK_KW => break_expr(p, r),
        _ => {
            p.err_recover("expected expression", EXPR_RECOVERY_SET);
            return None;
        }
    };
    let blocklike = match done.kind() {
        IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => BlockLike::Block,
        _ => BlockLike::NotBlock,
    };
    Some((done, blocklike))
}

// test tuple_expr
// fn foo() {
//     ();
//     (1);
//     (1,);
// }
fn tuple_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(L_PAREN));
    let m = p.start();
    p.expect(L_PAREN);

    let mut saw_comma = false;
    let mut saw_expr = false;
    while !p.at(EOF) && !p.at(R_PAREN) {
        saw_expr = true;
        if !p.at_ts(EXPR_FIRST) {
            p.error("expected expression");
            break;
        }
        expr(p);
        if !p.at(R_PAREN) {
            saw_comma = true;
            p.expect(COMMA);
        }
    }
    p.expect(R_PAREN);
    m.complete(
        p,
        if saw_expr && !saw_comma {
            PAREN_EXPR
        } else {
            TUPLE_EXPR
        },
    )
}

// test array_expr
// fn foo() {
//     [];
//     [1];
//     [1, 2,];
//     [1; 2];
// }
fn array_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(L_BRACK));
    let m = p.start();
    p.bump();
    if p.eat(R_BRACK) {
        return m.complete(p, ARRAY_EXPR);
    }
    expr(p);
    if p.eat(SEMI) {
        expr(p);
        p.expect(R_BRACK);
        return m.complete(p, ARRAY_EXPR);
    }
    while !p.at(EOF) && !p.at(R_BRACK) {
        p.expect(COMMA);
        if p.at(R_BRACK) {
            break;
        }
        if !p.at_ts(EXPR_FIRST) {
            p.error("expected expression");
            break;
        }
        expr(p);
    }
    p.expect(R_BRACK);
    m.complete(p, ARRAY_EXPR)
}

// test lambda_expr
// fn foo() {
//     || ();
//     || -> i32 { 92 };
//     |x| x;
//     move |x: i32,| x;
// }
fn lambda_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(PIPE) || (p.at(MOVE_KW) && p.nth(1) == PIPE));
    let m = p.start();
    p.eat(MOVE_KW);
    params::param_list_opt_types(p);
    if opt_fn_ret_type(p) {
        if !p.at(L_CURLY) {
            p.error("expected `{`");
        }
    }
    expr(p);
    m.complete(p, LAMBDA_EXPR)
}

// test if_expr
// fn foo() {
//     if true {};
//     if true {} else {};
//     if true {} else if false {} else {};
//     if S {};
// }
fn if_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(IF_KW));
    let m = p.start();
    p.bump();
    cond(p);
    block(p);
    if p.at(ELSE_KW) {
        p.bump();
        if p.at(IF_KW) {
            if_expr(p);
        } else {
            block(p);
        }
    }
    m.complete(p, IF_EXPR)
}

// test label
// fn foo() {
//     'a: loop {}
//     'b: while true {}
//     'c: for x in () {}
// }
fn label(p: &mut Parser) {
    assert!(p.at(LIFETIME) && p.nth(1) == COLON);
    let m = p.start();
    p.bump();
    p.bump();
    m.complete(p, LABEL);
}

// test loop_expr
// fn foo() {
//     loop {};
// }
fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
    assert!(p.at(LOOP_KW));
    let m = m.unwrap_or_else(|| p.start());
    p.bump();
    block(p);
    m.complete(p, LOOP_EXPR)
}

// test while_expr
// fn foo() {
//     while true {};
//     while let Some(x) = it.next() {};
// }
fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
    assert!(p.at(WHILE_KW));
    let m = m.unwrap_or_else(|| p.start());
    p.bump();
    cond(p);
    block(p);
    m.complete(p, WHILE_EXPR)
}

// test for_expr
// fn foo() {
//     for x in [] {};
// }
fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
    assert!(p.at(FOR_KW));
    let m = m.unwrap_or_else(|| p.start());
    p.bump();
    patterns::pattern(p);
    p.expect(IN_KW);
    expr_no_struct(p);
    block(p);
    m.complete(p, FOR_EXPR)
}

// test cond
// fn foo() { if let Some(_) = None {} }
fn cond(p: &mut Parser) {
    let m = p.start();
    if p.eat(LET_KW) {
        patterns::pattern(p);
        p.expect(EQ);
    }
    expr_no_struct(p);
    m.complete(p, CONDITION);
}

// test match_expr
// fn foo() {
//     match () { };
//     match S {};
// }
fn match_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(MATCH_KW));
    let m = p.start();
    p.bump();
    expr_no_struct(p);
    if p.at(L_CURLY) {
        match_arm_list(p);
    } else {
        p.error("expected `{`")
    }
    m.complete(p, MATCH_EXPR)
}

pub(crate) fn match_arm_list(p: &mut Parser) {
    assert!(p.at(L_CURLY));
    let m = p.start();
    p.eat(L_CURLY);
    while !p.at(EOF) && !p.at(R_CURLY) {
        if p.at(L_CURLY) {
            error_block(p, "expected match arm");
            continue;
        }
        // test match_arms_commas
        // fn foo() {
        //     match () {
        //         _ => (),
        //         _ => {}
        //         _ => ()
        //     }
        // }
        if match_arm(p).is_block() {
            p.eat(COMMA);
        } else if !p.at(R_CURLY) {
            p.expect(COMMA);
        }
    }
    p.expect(R_CURLY);
    m.complete(p, MATCH_ARM_LIST);
}

// test match_arm
// fn foo() {
//     match () {
//         _ => (),
//         _ if Test > Test{field: 0} => (),
//         X | Y if Z => (),
//         | X | Y if Z => (),
//         | X => (),
//     };
// }
fn match_arm(p: &mut Parser) -> BlockLike {
    let m = p.start();
    p.eat(PIPE);
    patterns::pattern_r(p, TokenSet::empty());
    while p.eat(PIPE) {
        patterns::pattern(p);
    }
    if p.eat(IF_KW) {
        expr(p);
    }
    p.expect(FAT_ARROW);
    let ret = expr_stmt(p);
    m.complete(p, MATCH_ARM);
    ret
}

// test block_expr
// fn foo() {
//     {};
//     unsafe {};
//     'label: {};
// }
fn block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
    assert!(p.at(L_CURLY));
    let m = m.unwrap_or_else(|| p.start());
    block(p);
    m.complete(p, BLOCK_EXPR)
}

// test return_expr
// fn foo() {
//     return;
//     return 92;
// }
fn return_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(RETURN_KW));
    let m = p.start();
    p.bump();
    if p.at_ts(EXPR_FIRST) {
        expr(p);
    }
    m.complete(p, RETURN_EXPR)
}

// test continue_expr
// fn foo() {
//     loop {
//         continue;
//         continue 'l;
//     }
// }
fn continue_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(CONTINUE_KW));
    let m = p.start();
    p.bump();
    p.eat(LIFETIME);
    m.complete(p, CONTINUE_EXPR)
}

// test break_expr
// fn foo() {
//     loop {
//         break;
//         break 'l;
//         break 92;
//         break 'l 92;
//     }
// }
fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
    assert!(p.at(BREAK_KW));
    let m = p.start();
    p.bump();
    p.eat(LIFETIME);
    // test break_ambiguity
    // fn foo(){
    //     if break {}
    //     while break {}
    //     for i in break {}
    //     match break {}
    // }
    if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(L_CURLY)) {
        expr(p);
    }
    m.complete(p, BREAK_EXPR)
}
<commit_msg>Dedupe PATH_FIRST in ATOM_EXPR_FIRST<commit_after>use super::*;
use crate::grammar::paths::PATH_FIRST;

// test expr_literals
// fn foo() {
//     let _ = true;
//     let _ = false;
//     let _ = 1;
//     let _ = 2.0;
//     let _ = b'a';
//     let _ = 'b';
//     let _ = "c";
//     let _ = r"d";
//     let _ = b"e";
//     let _ = br"f";
// }
pub(crate) const LITERAL_FIRST: TokenSet = token_set![
    TRUE_KW,
    FALSE_KW,
    INT_NUMBER,
    FLOAT_NUMBER,
    BYTE,
    CHAR,
    STRING,
    RAW_STRING,
    BYTE_STRING,
    RAW_BYTE_STRING
];

pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
    if !p.at_ts(LITERAL_FIRST) {
        return None;
    }
    let m = p.start();
    p.bump();
    Some(m.complete(p, LITERAL))
}

// E.g. for after the break in `if break {}`, this should not match
pub(super) const ATOM_EXPR_FIRST: TokenSet = LITERAL_FIRST.union(PATH_FIRST).union(token_set![
    L_PAREN,
    L_CURLY,
    L_BRACK,
    PIPE,
    MOVE_KW,
    IF_KW,
    WHILE_KW,
    MATCH_KW,
    UNSAFE_KW,
    RETURN_KW,
    BREAK_KW,
    CONTINUE_KW,
    LIFETIME,
]);

const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW];

pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
    if let Some(m) = literal(p) {
        return Some((m, BlockLike::NotBlock));
    }
    if paths::is_path_start(p) || p.at(L_ANGLE) {
        return Some(path_expr(p, r));
    }
    let la = p.nth(1);
    let done = match p.current() {
        L_PAREN => tuple_expr(p),
        L_BRACK => array_expr(p),
        PIPE => lambda_expr(p),
        MOVE_KW if la == PIPE => lambda_expr(p),
        IF_KW => if_expr(p),

        LOOP_KW => loop_expr(p, None),
        FOR_KW => for_expr(p, None),
        WHILE_KW => while_expr(p, None),
        LIFETIME if la == COLON => {
            let m = p.start();
            label(p);
            match p.current() {
                LOOP_KW => loop_expr(p, Some(m)),
                FOR_KW => for_expr(p, Some(m)),
                WHILE_KW => while_expr(p, Some(m)),
                L_CURLY => block_expr(p, Some(m)),
                _ => {
                    // test_err misplaced_label_err
                    // fn main() {
                    //     'loop: impl
                    // }
                    p.error("expected a loop");
                    m.complete(p, ERROR);
                    return None;
                }
            }
        }

        MATCH_KW => match_expr(p),
        UNSAFE_KW if la == L_CURLY => {
            let m = p.start();
            p.bump();
            block_expr(p, Some(m))
        }
        L_CURLY => block_expr(p, None),
        RETURN_KW => return_expr(p),
        CONTINUE_KW => continue_expr(p),
        BREAK_KW => break_expr(p, r),
        _ => {
            p.err_recover("expected expression", EXPR_RECOVERY_SET);
            return None;
        }
    };
    let blocklike = match done.kind() {
        IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => BlockLike::Block,
        _ => BlockLike::NotBlock,
    };
    Some((done, blocklike))
}

// test tuple_expr
// fn foo() {
//     ();
//     (1);
//     (1,);
// }
fn tuple_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(L_PAREN));
    let m = p.start();
    p.expect(L_PAREN);

    let mut saw_comma = false;
    let mut saw_expr = false;
    while !p.at(EOF) && !p.at(R_PAREN) {
        saw_expr = true;
        if !p.at_ts(EXPR_FIRST) {
            p.error("expected expression");
            break;
        }
        expr(p);
        if !p.at(R_PAREN) {
            saw_comma = true;
            p.expect(COMMA);
        }
    }
    p.expect(R_PAREN);
    m.complete(
        p,
        if saw_expr && !saw_comma {
            PAREN_EXPR
        } else {
            TUPLE_EXPR
        },
    )
}

// test array_expr
// fn foo() {
//     [];
//     [1];
//     [1, 2,];
//     [1; 2];
// }
fn array_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(L_BRACK));
    let m = p.start();
    p.bump();
    if p.eat(R_BRACK) {
        return m.complete(p, ARRAY_EXPR);
    }
    expr(p);
    if p.eat(SEMI) {
        expr(p);
        p.expect(R_BRACK);
        return m.complete(p, ARRAY_EXPR);
    }
    while !p.at(EOF) && !p.at(R_BRACK) {
        p.expect(COMMA);
        if p.at(R_BRACK) {
            break;
        }
        if !p.at_ts(EXPR_FIRST) {
            p.error("expected expression");
            break;
        }
        expr(p);
    }
    p.expect(R_BRACK);
    m.complete(p, ARRAY_EXPR)
}

// test lambda_expr
// fn foo() {
//     || ();
//     || -> i32 { 92 };
//     |x| x;
//     move |x: i32,| x;
// }
fn lambda_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(PIPE) || (p.at(MOVE_KW) && p.nth(1) == PIPE));
    let m = p.start();
    p.eat(MOVE_KW);
    params::param_list_opt_types(p);
    if opt_fn_ret_type(p) {
        if !p.at(L_CURLY) {
            p.error("expected `{`");
        }
    }
    expr(p);
    m.complete(p, LAMBDA_EXPR)
}

// test if_expr
// fn foo() {
//     if true {};
//     if true {} else {};
//     if true {} else if false {} else {};
//     if S {};
// }
fn if_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(IF_KW));
    let m = p.start();
    p.bump();
    cond(p);
    block(p);
    if p.at(ELSE_KW) {
        p.bump();
        if p.at(IF_KW) {
            if_expr(p);
        } else {
            block(p);
        }
    }
    m.complete(p, IF_EXPR)
}

// test label
// fn foo() {
//     'a: loop {}
//     'b: while true {}
//     'c: for x in () {}
// }
fn label(p: &mut Parser) {
    assert!(p.at(LIFETIME) && p.nth(1) == COLON);
    let m = p.start();
    p.bump();
    p.bump();
    m.complete(p, LABEL);
}

// test loop_expr
// fn foo() {
//     loop {};
// }
fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
    assert!(p.at(LOOP_KW));
    let m = m.unwrap_or_else(|| p.start());
    p.bump();
    block(p);
    m.complete(p, LOOP_EXPR)
}

// test while_expr
// fn foo() {
//     while true {};
//     while let Some(x) = it.next() {};
// }
fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
    assert!(p.at(WHILE_KW));
    let m = m.unwrap_or_else(|| p.start());
    p.bump();
    cond(p);
    block(p);
    m.complete(p, WHILE_EXPR)
}

// test for_expr
// fn foo() {
//     for x in [] {};
// }
fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
    assert!(p.at(FOR_KW));
    let m = m.unwrap_or_else(|| p.start());
    p.bump();
    patterns::pattern(p);
    p.expect(IN_KW);
    expr_no_struct(p);
    block(p);
    m.complete(p, FOR_EXPR)
}

// test cond
// fn foo() { if let Some(_) = None {} }
fn cond(p: &mut Parser) {
    let m = p.start();
    if p.eat(LET_KW) {
        patterns::pattern(p);
        p.expect(EQ);
    }
    expr_no_struct(p);
    m.complete(p, CONDITION);
}

// test match_expr
// fn foo() {
//     match () { };
//     match S {};
// }
fn match_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(MATCH_KW));
    let m = p.start();
    p.bump();
    expr_no_struct(p);
    if p.at(L_CURLY) {
        match_arm_list(p);
    } else {
        p.error("expected `{`")
    }
    m.complete(p, MATCH_EXPR)
}

pub(crate) fn match_arm_list(p: &mut Parser) {
    assert!(p.at(L_CURLY));
    let m = p.start();
    p.eat(L_CURLY);
    while !p.at(EOF) && !p.at(R_CURLY) {
        if p.at(L_CURLY) {
            error_block(p, "expected match arm");
            continue;
        }
        // test match_arms_commas
        // fn foo() {
        //     match () {
        //         _ => (),
        //         _ => {}
        //         _ => ()
        //     }
        // }
        if match_arm(p).is_block() {
            p.eat(COMMA);
        } else if !p.at(R_CURLY) {
            p.expect(COMMA);
        }
    }
    p.expect(R_CURLY);
    m.complete(p, MATCH_ARM_LIST);
}

// test match_arm
// fn foo() {
//     match () {
//         _ => (),
//         _ if Test > Test{field: 0} => (),
//         X | Y if Z => (),
//         | X | Y if Z => (),
//         | X => (),
//     };
// }
fn match_arm(p: &mut Parser) -> BlockLike {
    let m = p.start();
    p.eat(PIPE);
    patterns::pattern_r(p, TokenSet::empty());
    while p.eat(PIPE) {
        patterns::pattern(p);
    }
    if p.eat(IF_KW) {
        expr(p);
    }
    p.expect(FAT_ARROW);
    let ret = expr_stmt(p);
    m.complete(p, MATCH_ARM);
    ret
}

// test block_expr
// fn foo() {
//     {};
//     unsafe {};
//     'label: {};
// }
fn block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
    assert!(p.at(L_CURLY));
    let m = m.unwrap_or_else(|| p.start());
    block(p);
    m.complete(p, BLOCK_EXPR)
}

// test return_expr
// fn foo() {
//     return;
//     return 92;
// }
fn return_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(RETURN_KW));
    let m = p.start();
    p.bump();
    if p.at_ts(EXPR_FIRST) {
        expr(p);
    }
    m.complete(p, RETURN_EXPR)
}

// test continue_expr
// fn foo() {
//     loop {
//         continue;
//         continue 'l;
//     }
// }
fn continue_expr(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(CONTINUE_KW));
    let m = p.start();
    p.bump();
    p.eat(LIFETIME);
    m.complete(p, CONTINUE_EXPR)
}

// test break_expr
// fn foo() {
//     loop {
//         break;
//         break 'l;
//         break 92;
//         break 'l 92;
//     }
// }
fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
    assert!(p.at(BREAK_KW));
    let m = p.start();
    p.bump();
    p.eat(LIFETIME);
    // test break_ambiguity
    // fn foo(){
    //     if break {}
    //     while break {}
    //     for i in break {}
    //     match break {}
    // }
    if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(L_CURLY)) {
        expr(p);
    }
    m.complete(p, BREAK_EXPR)
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::time::SystemTime;

use anyhow::Result;
use chrono::prelude::*;
use log::{debug, error, info};
use serde_derive::{Deserialize, Serialize};

use crate::settings::Settings;
use crate::task::{Task, TaskResult, TaskStatus};

pub type SharedState = Arc<Mutex<State>>;

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct State {
    max_id: usize,
    pub settings: Settings,
    pub running: bool,
    pub tasks: BTreeMap<usize, Task>,
    /// Represents whether the group is currently paused or running
    pub groups: HashMap<String, bool>,
    config_path: Option<PathBuf>,
}

/// This is the full representation of the current state of the Pueue daemon.
/// This includes
/// - All settings.
/// - The full task list
/// - The current status of all tasks
///
/// However, the State does NOT include:
/// - Information about child processes
/// - Handles to child processes
///
/// That information is saved in the TaskHandler.
impl State {
    pub fn new(settings: &Settings, config_path: Option<PathBuf>) -> State {
        // Create a default group state.
        let mut groups = HashMap::new();
        for group in settings.daemon.groups.keys() {
            groups.insert(group.into(), true);
        }

        let mut state = State {
            max_id: 0,
            settings: settings.clone(),
            running: true,
            tasks: BTreeMap::new(),
            groups,
            config_path,
        };
        state.restore();
        state.save();
        state
    }

    pub fn add_task(&mut self, mut task: Task) -> usize {
        task.id = self.max_id;
        self.tasks.insert(self.max_id, task);
        self.max_id += 1;
        self.save();
        self.max_id - 1
    }

    pub fn change_status(&mut self, id: usize, new_status: TaskStatus) {
        if let Some(ref mut task) = self.tasks.get_mut(&id) {
            task.status = new_status;
            self.save();
        };
    }

    pub fn set_enqueue_at(&mut self, id: usize, enqueue_at: Option<DateTime<Local>>) {
        if let Some(ref mut task) = self.tasks.get_mut(&id) {
            task.enqueue_at = enqueue_at;
        }
    }

    /// Check if the given group already exists.
    /// If it doesn't exist yet, create a state entry and a new settings entry.
    pub fn create_group(&mut self, group: &str) -> Result<()> {
        if self.settings.daemon.groups.get(group).is_none() {
            self.settings.daemon.groups.insert(group.into(), 1);
        }
        if self.groups.get(group).is_none() {
            self.groups.insert(group.into(), true);
        }

        self.save();
        self.save_settings()
    }

    /// Remove a group.
    /// Also go through all tasks and set the removed group to `None`.
    pub fn remove_group(&mut self, group: &str) -> Result<()> {
        self.settings.daemon.groups.remove(group);
        self.groups.remove(group);

        // Reset all tasks with removed group to the default
        for (_, task) in self.tasks.iter_mut() {
            if let Some(group_name) = &task.group {
                if group_name == group {
                    task.group = None;
                }
            }
        }

        self.save();
        self.save_settings()
    }

    /// Set the running status for all groups including the default queue
    pub fn set_status_for_all_groups(&mut self, status: bool) {
        self.running = status;
        let keys = self.groups.keys().cloned().collect::<Vec<String>>();
        for key in keys {
            self.groups.insert(key, status);
        }
        self.save()
    }

    /// Get all task ids of a specific group
    pub fn task_ids_in_group_with_stati(
        &mut self,
        group: &Option<String>,
        stati: Vec<TaskStatus>,
    ) -> Vec<usize> {
        self.tasks
            .iter()
            .filter(|(_, task)| stati.contains(&task.status))
            .filter(|(_, task)| group == &task.group)
            .map(|(id, _)| *id)
            .collect()
    }

    /// This checks, whether the given task_ids are in the specified statuses.
    /// The first result is the list of task_ids that match these statuses.
    /// The second result is the list of task_ids that don't match these statuses.
    ///
    /// Additionally, a list of task_ids can be specified to only run the check
    /// on a subset of all tasks.
    pub fn tasks_in_statuses(
        &mut self,
        statuses: Vec<TaskStatus>,
        task_ids: Option<Vec<usize>>,
    ) -> (Vec<usize>, Vec<usize>) {
        let task_ids = match task_ids {
            Some(ids) => ids,
            None => self.tasks.keys().cloned().collect(),
        };

        let mut matching = Vec::new();
        let mut mismatching = Vec::new();

        // Filter all task id's that match the provided statuses.
        for task_id in task_ids.iter() {
            // Check whether the task exists and save all non-existing task ids.
            match self.tasks.get(&task_id) {
                None => {
                    mismatching.push(*task_id);
                    continue;
                }
                Some(task) => {
                    // Check whether the task status matches the specified statuses.
                    if statuses.contains(&task.status) {
                        matching.push(*task_id);
                    } else {
                        mismatching.push(*task_id);
                    }
                }
            };
        }

        (matching, mismatching)
    }

    /// Pause the daemon, if the settings say so.
    /// Always pause the respective queue/group of the task.
    pub fn handle_task_failure(&mut self, group: Option<String>) {
        if self.settings.daemon.pause_on_failure {
            if let Some(group) = group {
                self.groups.insert(group.clone(), false);
            } else {
                self.running = false;
            }
        }
    }

    pub fn reset(&mut self) {
        self.backup();
        self.max_id = 0;
        self.tasks = BTreeMap::new();
        self.set_status_for_all_groups(true);
    }

    pub fn save_settings(&mut self) -> Result<()> {
        self.settings.save(&self.config_path)
    }

    /// Convenience wrapper around save_to_file.
    pub fn save(&mut self) {
        self.save_to_file(false);
    }

    /// Save the current current state in a file with a timestamp.
    /// At the same time remove old state logs from the log directory.
    /// This function is called, when large changes to the state are applied, e.g. clean/reset.
    pub fn backup(&mut self) {
        self.save_to_file(true);
        if let Err(error) = self.rotate() {
            error!("Failed to rotate files: {:?}", error);
        };
    }

    /// Save the current state to disk.
    /// We do this to restore in case of a crash.
    /// If log == true, the file will be saved with a time stamp.
    ///
    /// In comparison to the daemon -> client communication, the state is saved
    /// as JSON for better readability and debug purposes.
    fn save_to_file(&mut self, log: bool) {
        let serialized = serde_json::to_string(&self);
        if let Err(error) = serialized {
            error!("Failed to serialize state: {:?}", error);
            return;
        }

        let serialized = serialized.unwrap();

        let path = Path::new(&self.settings.shared.pueue_directory);
        let (temp, real) = if log {
            let path = path.join("log");
            let now: DateTime<Utc> = Utc::now();
            let time = now.format("%Y-%m-%d_%H-%M-%S");
            (
                path.join(format!("{}_state.json.partial", time)),
                path.join(format!("{}_state.json", time)),
            )
        } else {
            (path.join("state.json.partial"), path.join("state.json"))
        };

        // Write to temporary log file first, to prevent loss due to crashes.
        if let Err(error) = fs::write(&temp, serialized) {
            error!(
                "Failed to write log to directory. File permissions? Error: {:?}",
                error
            );
            return;
        }

        // Overwrite the original with the temp file, if everything went fine.
        if let Err(error) = fs::rename(&temp, &real) {
            error!(
                "Failed to overwrite old log file. File permissions? Error: {:?}",
                error
            );
            return;
        }

        if log {
            debug!("State backup created at: {:?}", real);
        } else {
            debug!("State saved at: {:?}", real);
        }
    }

    /// Restore the last state from a previous session.
    /// The state is stored as json in the log directory.
    fn restore(&mut self) {
        let path = Path::new(&self.settings.shared.pueue_directory).join("state.json");

        // Ignore if the file doesn't exist. It doesn't have to.
        if !path.exists() {
            info!(
                "Couldn't find state from previous session at location: {:?}",
                path
            );
            return;
        }
        info!("Start restoring state");

        // Try to load the file.
        let data = fs::read_to_string(&path);
        if let Err(error) = data {
            error!("Failed to read previous state log: {:?}", error);
            return;
        }
        let data = data.unwrap();

        // Try to deserialize the state file.
        let deserialized: Result<State, serde_json::error::Error> = serde_json::from_str(&data);
        if let Err(error) = deserialized {
            error!("Failed to deserialize previous state log: {:?}", error);
            return;
        }
        let mut state = deserialized.unwrap();

        // Restore the state from the file.
        // While restoring the tasks, check for any invalid/broken stati.
        for (task_id, task) in state.tasks.iter_mut() {
            // Handle ungraceful shutdowns while executing tasks.
            if task.status == TaskStatus::Running || task.status == TaskStatus::Paused {
                info!(
                    "Setting task {} with previous status {:?} to new status {:?}",
                    task.id,
                    task.status,
                    TaskResult::Killed
                );
                task.status = TaskStatus::Done;
                task.result = Some(TaskResult::Killed);
            }
            // Crash during editing of the task command.
            if task.status == TaskStatus::Locked {
                task.status = TaskStatus::Stashed;
            }
            // If there are any queued tasks, pause the daemon.
            // This should prevent any unwanted execution of tasks due to a system crash.
            if task.status == TaskStatus::Queued {
                info!("Pausing daemon to prevent unwanted execution of previous tasks");
                state.running = false;
            }

            self.tasks.insert(*task_id, task.clone());
        }

        if !self.running {
            // If the daemon isn't running, stop all groups.
            for group in self.settings.daemon.groups.keys() {
                self.groups.insert(group.into(), false);
            }
        } else {
            // If the daemon running, apply all running group states from the previous state.
            for (group, running) in state.groups.iter() {
                if self.groups.contains_key(group) {
                    self.groups.insert(group.into(), *running);
                }
            }
        }

        // Go trough all tasks and set all groups that are no longer
        // listed in the configuration file to the default.
        for (_, task) in self.tasks.iter_mut() {
            if let Some(group) = &task.group {
                if !self.groups.contains_key(group) {
                    task.group = None;
                }
            }
        }

        self.running = state.running;
        self.max_id = state.max_id;
    }

    /// Remove old logs that aren't needed any longer.
    fn rotate(&mut self) -> Result<()> {
        let path = Path::new(&self.settings.shared.pueue_directory);
        let path = path.join("log");

        // Get all log files in the directory with their respective system time.
        let mut entries: BTreeMap<SystemTime, PathBuf> = BTreeMap::new();
        let mut directory_list = fs::read_dir(path)?;
        while let Some(Ok(entry)) = directory_list.next() {
            let path = entry.path();

            let metadata = entry.metadata()?;
            let time = metadata.modified()?;
            entries.insert(time, path);
        }

        // Remove all files above the threshold.
        // Old files are removed first (implictly by the BTree order).
        let mut number_entries = entries.len();
        let mut iter = entries.iter();
        while number_entries > 10 {
            if let Some((_, path)) = iter.next() {
                fs::remove_file(path)?;
                number_entries -= 1;
            }
        }

        Ok(())
    }
}
<commit_msg>Remove clippy issue<commit_after>use std::collections::BTreeMap;
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::time::SystemTime;

use anyhow::Result;
use chrono::prelude::*;
use log::{debug, error, info};
use serde_derive::{Deserialize, Serialize};

use crate::settings::Settings;
use crate::task::{Task, TaskResult, TaskStatus};

pub type SharedState = Arc<Mutex<State>>;

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct State {
    max_id: usize,
    pub settings: Settings,
    pub running: bool,
    pub tasks: BTreeMap<usize, Task>,
    /// Represents whether the group is currently paused or running
    pub groups: HashMap<String, bool>,
    config_path: Option<PathBuf>,
}

/// This is the full representation of the current state of the Pueue daemon.
/// This includes
/// - All settings.
/// - The full task list
/// - The current status of all tasks
///
/// However, the State does NOT include:
/// - Information about child processes
/// - Handles to child processes
///
/// That information is saved in the TaskHandler.
impl State {
    pub fn new(settings: &Settings, config_path: Option<PathBuf>) -> State {
        // Create a default group state.
        let mut groups = HashMap::new();
        for group in settings.daemon.groups.keys() {
            groups.insert(group.into(), true);
        }

        let mut state = State {
            max_id: 0,
            settings: settings.clone(),
            running: true,
            tasks: BTreeMap::new(),
            groups,
            config_path,
        };
        state.restore();
        state.save();
        state
    }

    pub fn add_task(&mut self, mut task: Task) -> usize {
        task.id = self.max_id;
        self.tasks.insert(self.max_id, task);
        self.max_id += 1;
        self.save();
        self.max_id - 1
    }

    pub fn change_status(&mut self, id: usize, new_status: TaskStatus) {
        if let Some(ref mut task) = self.tasks.get_mut(&id) {
            task.status = new_status;
            self.save();
        };
    }

    pub fn set_enqueue_at(&mut self, id: usize, enqueue_at: Option<DateTime<Local>>) {
        if let Some(ref mut task) = self.tasks.get_mut(&id) {
            task.enqueue_at = enqueue_at;
        }
    }

    /// Check if the given group already exists.
    /// If it doesn't exist yet, create a state entry and a new settings entry.
    pub fn create_group(&mut self, group: &str) -> Result<()> {
        if self.settings.daemon.groups.get(group).is_none() {
            self.settings.daemon.groups.insert(group.into(), 1);
        }
        if self.groups.get(group).is_none() {
            self.groups.insert(group.into(), true);
        }

        self.save();
        self.save_settings()
    }

    /// Remove a group.
    /// Also go through all tasks and set the removed group to `None`.
    pub fn remove_group(&mut self, group: &str) -> Result<()> {
        self.settings.daemon.groups.remove(group);
        self.groups.remove(group);

        // Reset all tasks with removed group to the default
        for (_, task) in self.tasks.iter_mut() {
            if let Some(group_name) = &task.group {
                if group_name == group {
                    task.group = None;
                }
            }
        }

        self.save();
        self.save_settings()
    }

    /// Set the running status for all groups including the default queue
    pub fn set_status_for_all_groups(&mut self, status: bool) {
        self.running = status;
        let keys = self.groups.keys().cloned().collect::<Vec<String>>();
        for key in keys {
            self.groups.insert(key, status);
        }
        self.save()
    }

    /// Get all task ids of a specific group
    pub fn task_ids_in_group_with_stati(
        &mut self,
        group: &Option<String>,
        stati: Vec<TaskStatus>,
    ) -> Vec<usize> {
        self.tasks
            .iter()
            .filter(|(_, task)| stati.contains(&task.status))
            .filter(|(_, task)| group == &task.group)
            .map(|(id, _)| *id)
            .collect()
    }

    /// This checks, whether the given task_ids are in the specified statuses.
    /// The first result is the list of task_ids that match these statuses.
    /// The second result is the list of task_ids that don't match these statuses.
    ///
    /// Additionally, a list of task_ids can be specified to only run the check
    /// on a subset of all tasks.
    pub fn tasks_in_statuses(
        &mut self,
        statuses: Vec<TaskStatus>,
        task_ids: Option<Vec<usize>>,
    ) -> (Vec<usize>, Vec<usize>) {
        let task_ids = match task_ids {
            Some(ids) => ids,
            None => self.tasks.keys().cloned().collect(),
        };

        let mut matching = Vec::new();
        let mut mismatching = Vec::new();

        // Filter all task id's that match the provided statuses.
        for task_id in task_ids.iter() {
            // Check whether the task exists and save all non-existing task ids.
            match self.tasks.get(&task_id) {
                None => {
                    mismatching.push(*task_id);
                    continue;
                }
                Some(task) => {
                    // Check whether the task status matches the specified statuses.
                    if statuses.contains(&task.status) {
                        matching.push(*task_id);
                    } else {
                        mismatching.push(*task_id);
                    }
                }
            };
        }

        (matching, mismatching)
    }

    /// Pause the daemon, if the settings say so.
    /// Always pause the respective queue/group of the task.
    pub fn handle_task_failure(&mut self, group: Option<String>) {
        if self.settings.daemon.pause_on_failure {
            if let Some(group) = group {
                self.groups.insert(group, false);
            } else {
                self.running = false;
            }
        }
    }

    pub fn reset(&mut self) {
        self.backup();
        self.max_id = 0;
        self.tasks = BTreeMap::new();
        self.set_status_for_all_groups(true);
    }

    pub fn save_settings(&mut self) -> Result<()> {
        self.settings.save(&self.config_path)
    }

    /// Convenience wrapper around save_to_file.
    pub fn save(&mut self) {
        self.save_to_file(false);
    }

    /// Save the current current state in a file with a timestamp.
    /// At the same time remove old state logs from the log directory.
    /// This function is called, when large changes to the state are applied, e.g. clean/reset.
    pub fn backup(&mut self) {
        self.save_to_file(true);
        if let Err(error) = self.rotate() {
            error!("Failed to rotate files: {:?}", error);
        };
    }

    /// Save the current state to disk.
    /// We do this to restore in case of a crash.
    /// If log == true, the file will be saved with a time stamp.
    ///
    /// In comparison to the daemon -> client communication, the state is saved
    /// as JSON for better readability and debug purposes.
    fn save_to_file(&mut self, log: bool) {
        let serialized = serde_json::to_string(&self);
        if let Err(error) = serialized {
            error!("Failed to serialize state: {:?}", error);
            return;
        }

        let serialized = serialized.unwrap();

        let path = Path::new(&self.settings.shared.pueue_directory);
        let (temp, real) = if log {
            let path = path.join("log");
            let now: DateTime<Utc> = Utc::now();
            let time = now.format("%Y-%m-%d_%H-%M-%S");
            (
                path.join(format!("{}_state.json.partial", time)),
                path.join(format!("{}_state.json", time)),
            )
        } else {
            (path.join("state.json.partial"), path.join("state.json"))
        };

        // Write to temporary log file first, to prevent loss due to crashes.
        if let Err(error) = fs::write(&temp, serialized) {
            error!(
                "Failed to write log to directory. File permissions? Error: {:?}",
                error
            );
            return;
        }

        // Overwrite the original with the temp file, if everything went fine.
        if let Err(error) = fs::rename(&temp, &real) {
            error!(
                "Failed to overwrite old log file. File permissions? Error: {:?}",
                error
            );
            return;
        }

        if log {
            debug!("State backup created at: {:?}", real);
        } else {
            debug!("State saved at: {:?}", real);
        }
    }

    /// Restore the last state from a previous session.
    /// The state is stored as json in the log directory.
    fn restore(&mut self) {
        let path = Path::new(&self.settings.shared.pueue_directory).join("state.json");

        // Ignore if the file doesn't exist. It doesn't have to.
        if !path.exists() {
            info!(
                "Couldn't find state from previous session at location: {:?}",
                path
            );
            return;
        }
        info!("Start restoring state");

        // Try to load the file.
        let data = fs::read_to_string(&path);
        if let Err(error) = data {
            error!("Failed to read previous state log: {:?}", error);
            return;
        }
        let data = data.unwrap();

        // Try to deserialize the state file.
        let deserialized: Result<State, serde_json::error::Error> = serde_json::from_str(&data);
        if let Err(error) = deserialized {
            error!("Failed to deserialize previous state log: {:?}", error);
            return;
        }
        let mut state = deserialized.unwrap();

        // Restore the state from the file.
        // While restoring the tasks, check for any invalid/broken stati.
        for (task_id, task) in state.tasks.iter_mut() {
            // Handle ungraceful shutdowns while executing tasks.
            if task.status == TaskStatus::Running || task.status == TaskStatus::Paused {
                info!(
                    "Setting task {} with previous status {:?} to new status {:?}",
                    task.id,
                    task.status,
                    TaskResult::Killed
                );
                task.status = TaskStatus::Done;
                task.result = Some(TaskResult::Killed);
            }
            // Crash during editing of the task command.
            if task.status == TaskStatus::Locked {
                task.status = TaskStatus::Stashed;
            }
            // If there are any queued tasks, pause the daemon.
            // This should prevent any unwanted execution of tasks due to a system crash.
            if task.status == TaskStatus::Queued {
                info!("Pausing daemon to prevent unwanted execution of previous tasks");
                state.running = false;
            }

            self.tasks.insert(*task_id, task.clone());
        }

        if !self.running {
            // If the daemon isn't running, stop all groups.
            for group in self.settings.daemon.groups.keys() {
                self.groups.insert(group.into(), false);
            }
        } else {
            // If the daemon running, apply all running group states from the previous state.
            for (group, running) in state.groups.iter() {
                if self.groups.contains_key(group) {
                    self.groups.insert(group.into(), *running);
                }
            }
        }

        // Go trough all tasks and set all groups that are no longer
        // listed in the configuration file to the default.
        for (_, task) in self.tasks.iter_mut() {
            if let Some(group) = &task.group {
                if !self.groups.contains_key(group) {
                    task.group = None;
                }
            }
        }

        self.running = state.running;
        self.max_id = state.max_id;
    }

    /// Remove old logs that aren't needed any longer.
    fn rotate(&mut self) -> Result<()> {
        let path = Path::new(&self.settings.shared.pueue_directory);
        let path = path.join("log");

        // Get all log files in the directory with their respective system time.
        let mut entries: BTreeMap<SystemTime, PathBuf> = BTreeMap::new();
        let mut directory_list = fs::read_dir(path)?;
        while let Some(Ok(entry)) = directory_list.next() {
            let path = entry.path();

            let metadata = entry.metadata()?;
            let time = metadata.modified()?;
            entries.insert(time, path);
        }

        // Remove all files above the threshold.
        // Old files are removed first (implictly by the BTree order).
        let mut number_entries = entries.len();
        let mut iter = entries.iter();
        while number_entries > 10 {
            if let Some((_, path)) = iter.next() {
                fs::remove_file(path)?;
                number_entries -= 1;
            }
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use core::intrinsics::{volatile_load, volatile_store};
use raw_cpuid::CpuId;
use x86_64::registers::msr::*;

use memory::{ActivePageTable, MemoryController, Frame};
use memory::paging::Page;
use memory::paging::{VirtualAddress, PhysicalAddress};
use memory::paging::entry;

/// Bind containing an instance of the LocalApic struct
pub static mut LOCAL_APIC: LocalApic = LocalApic {
    base: 0,
    x2_support: false
};

/// Initialize the Local APIC system
pub unsafe fn init(memory_controller: &mut MemoryController) {
    LOCAL_APIC.init(memory_controller);
}

/// End of interrupt register
const APIC_REG_EOI: u32 = 0xb0;
/// Interrupt Control Register (low)
const APIC_REG_ICR_LOW: u32 = 0x300;
/// Interrupt Control Register (higher)
const APIC_REG_ICR_HIGH: u32 = 0x310;
/// Timer Local Vector Table Entry
const APIC_REG_TIMER_LOCAL_VECTOR: u32 = 0x320;
/// Timer Initial Count Register
const APIC_REG_TIMER_INIT_COUNT: u32 = 0x380;
/// Timer Divide Configuration Register
const APIC_REG_TIMER_DIVIDE: u32 = 0x3e0;

/// Local APIC
pub struct LocalApic {
    base: usize,
    x2_support: bool
}

impl LocalApic {
    /// Initialize the Local APIC system
    pub fn init(&mut self, memory_controller: &mut MemoryController) {
        // get the Local APIC base address
        self.base = rdmsr(IA32_APIC_BASE) as usize & 0xFFFF0000;

        // check if the x2APIC is supported
        self.x2_support = CpuId::new().get_feature_info().unwrap().has_x2apic();

        if ! self.x2_support {
            let page = Page::containing_address(self.base as VirtualAddress);
            let frame = Frame::containing_address(self.base as PhysicalAddress);
            memory_controller.map_to(page, frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);

            // flush TLB
            memory_controller.flush_all();
        }

        self.init_ap();

        // enable timer
        self.enable_timer();

        println!("APIC: Initialized!\n\tBase address: 0x{:>016x}\n\tx2APIC support: {:#?}", self.base, self.x2_support);
    }

    /// Enable LAPIC.
    ///
    /// Whether the X2APIC is supported we enable it too.
    fn init_ap(&mut self) {
        unsafe {
            if self.x2_support {
                wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10);
                wrmsr(IA32_X2APIC_SIVR, 0x100);
            } else {
                self.write(0xf0, 0x100);
            }
        }
    }

    /// Change the value of a LAPIC register.
    ///
    /// ## Parameters
    /// - `reg`: register offset
    /// - `value`: register value
    fn write(&self, reg: u32, value: u32) {
        unsafe {
            volatile_store((self.base + reg as usize) as *mut u32, value);
        }
    }

    /// Read a LAPIC register.
    ///
    /// ## Parameters
    /// - `reg`: register offset
    ///
    /// ## Returns
    /// The register value.
    fn read(&self, reg: u32) -> u32 {
        unsafe {
            volatile_load((self.base + reg as usize) as *const u32)
        }
    }

    /// Read the Interrupt Command Register (ICR).
    ///
    /// ## Returns
    /// The value of the ICR register.
    pub fn icr(&self) -> u64 {
        if self.x2_support {
            unsafe { rdmsr(IA32_X2APIC_ICR) }
        } else {
            unsafe {
                (self.read(APIC_REG_ICR_HIGH) as u64) << 32 | self.read(APIC_REG_ICR_LOW) as u64
            }
        }
    }

    /// Set the value for the Interrupt Command Register (ICR).
    ///
    /// ## Parameters
    /// - `value`: new value for the register.
    pub fn set_icr(&self, value: u64) {
        if self.x2_support {
            unsafe { wrmsr(IA32_X2APIC_ICR, value); }
        } else {
            unsafe {
                while self.read(APIC_REG_ICR_LOW) & 1 << 12 == 1 << 12 {}
                self.write(APIC_REG_ICR_HIGH, (value >> 32) as u32);
                self.write(APIC_REG_ICR_LOW, value as u32);
                while self.read(APIC_REG_ICR_LOW) & 1 << 12 == 1 << 12 { }
            }
        }
    }

    /// Throw an Inter-Processor Interrupt.
    ///
    /// ## Parameters
    /// - `apic_id`: LAPIC's ID of destination.
    pub fn inter_processor_interrupt(&mut self, apic_id: usize) {
        let mut icr = 0x4040;

        // Set the destination
        if self.x2_support {
            // bits 63:32
            icr |= (apic_id as u64) << 32;
        } else {
            // bits 63:56
            icr |= (apic_id as u64) << 56;
        }

        // set the ICR register
        self.set_icr(icr);
    }

    /// Specific End of Interrupt
    pub fn end_of_interrupt(&mut self) {
        unsafe {
            if self.x2_support {
                wrmsr(IA32_X2APIC_EOI, 0);
            } else {
                self.write(APIC_REG_EOI, 0)
            }
        }
    }

    /// Enable timer.
    pub fn enable_timer(&mut self) {
        unsafe {
            // Set the divider amount
            wrmsr(APIC_REG_TIMER_DIVIDE, 0x3);

            // Set the start count value
            wrmsr(APIC_REG_TIMER_INIT_COUNT, 0x10000);

            // Enable the time interrupt
            wrmsr(APIC_REG_TIMER_LOCAL_VECTOR, (1<<17) | 0x40);
        }
    }
}
<commit_msg>Use the right functions to write to the APIC<commit_after>use core::intrinsics::{volatile_load, volatile_store};
use raw_cpuid::CpuId;
use x86_64::registers::msr::*;

use memory::{ActivePageTable, MemoryController, Frame};
use memory::paging::Page;
use memory::paging::{VirtualAddress, PhysicalAddress};
use memory::paging::entry;

/// Bind containing an instance of the LocalApic struct
pub static mut LOCAL_APIC: LocalApic = LocalApic {
    base: 0,
    x2_support: false
};

/// Initialize the Local APIC system
pub unsafe fn init(memory_controller: &mut MemoryController) {
    LOCAL_APIC.init(memory_controller);
}

/// End of interrupt register
const APIC_REG_EOI: u32 = 0xb0;
/// Interrupt Control Register (low)
const APIC_REG_ICR_LOW: u32 = 0x300;
/// Interrupt Control Register (higher)
const APIC_REG_ICR_HIGH: u32 = 0x310;
/// Timer Local Vector Table Entry
const APIC_REG_TIMER_LOCAL_VECTOR: u32 = 0x320;
/// Timer Initial Count Register
const APIC_REG_TIMER_INIT_COUNT: u32 = 0x380;
/// Timer Divide Configuration Register
const APIC_REG_TIMER_DIVIDE: u32 = 0x3e0;

/// Local APIC
pub struct LocalApic {
    base: usize,
    x2_support: bool
}

impl LocalApic {
    /// Initialize the Local APIC system
    pub fn init(&mut self, memory_controller: &mut MemoryController) {
        // get the Local APIC base address
        self.base = rdmsr(IA32_APIC_BASE) as usize & 0xFFFF0000;

        // check if the x2APIC is supported
        self.x2_support = CpuId::new().get_feature_info().unwrap().has_x2apic();

        if ! self.x2_support {
            let page = Page::containing_address(self.base as VirtualAddress);
            let frame = Frame::containing_address(self.base as PhysicalAddress);
            memory_controller.map_to(page, frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);

            // flush TLB
            memory_controller.flush_all();
        }

        self.init_ap();

        // enable timer
        self.enable_timer();

        println!("APIC: Initialized!\n\tBase address: 0x{:>016x}\n\tx2APIC support: {:#?}", self.base, self.x2_support);
    }

    /// Enable LAPIC.
    ///
    /// Whether the X2APIC is supported we enable it too.
    fn init_ap(&mut self) {
        unsafe {
            if self.x2_support {
                wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10);
                wrmsr(IA32_X2APIC_SIVR, 0x100);
            } else {
                self.write(0xf0, 0x100);
            }
        }
    }

    /// Change the value of a LAPIC register.
    ///
    /// ## Parameters
    /// - `reg`: register offset
    /// - `value`: register value
    fn write(&self, reg: u32, value: u32) {
        unsafe {
            volatile_store((self.base + reg as usize) as *mut u32, value);
        }
    }

    /// Read a LAPIC register.
    ///
    /// ## Parameters
    /// - `reg`: register offset
    ///
    /// ## Returns
    /// The register value.
    fn read(&self, reg: u32) -> u32 {
        unsafe {
            volatile_load((self.base + reg as usize) as *const u32)
        }
    }

    /// Read the Interrupt Command Register (ICR).
    ///
    /// ## Returns
    /// The value of the ICR register.
    pub fn icr(&self) -> u64 {
        if self.x2_support {
            unsafe { rdmsr(IA32_X2APIC_ICR) }
        } else {
            unsafe {
                (self.read(APIC_REG_ICR_HIGH) as u64) << 32 | self.read(APIC_REG_ICR_LOW) as u64
            }
        }
    }

    /// Set the value for the Interrupt Command Register (ICR).
    ///
    /// ## Parameters
    /// - `value`: new value for the register.
    pub fn set_icr(&self, value: u64) {
        if self.x2_support {
            unsafe { wrmsr(IA32_X2APIC_ICR, value); }
        } else {
            unsafe {
                while self.read(APIC_REG_ICR_LOW) & 1 << 12 == 1 << 12 {}
                self.write(APIC_REG_ICR_HIGH, (value >> 32) as u32);
                self.write(APIC_REG_ICR_LOW, value as u32);
                while self.read(APIC_REG_ICR_LOW) & 1 << 12 == 1 << 12 { }
            }
        }
    }

    /// Throw an Inter-Processor Interrupt.
    ///
    /// ## Parameters
    /// - `apic_id`: LAPIC's ID of destination.
    pub fn inter_processor_interrupt(&mut self, apic_id: usize) {
        let mut icr = 0x4040;

        // Set the destination
        if self.x2_support {
            // bits 63:32
            icr |= (apic_id as u64) << 32;
        } else {
            // bits 63:56
            icr |= (apic_id as u64) << 56;
        }

        // set the ICR register
        self.set_icr(icr);
    }

    /// Specific End of Interrupt
    pub fn end_of_interrupt(&mut self) {
        unsafe {
            if self.x2_support {
                wrmsr(IA32_X2APIC_EOI, 0);
            } else {
                self.write(APIC_REG_EOI, 0)
            }
        }
    }

    /// Enable timer.
    pub fn enable_timer(&mut self) {
        unsafe {
            // Set the divider amount
            self.write(APIC_REG_TIMER_DIVIDE, 0x3);

            // Set the start count value
            self.write(APIC_REG_TIMER_INIT_COUNT, 0x10000);

            // Enable the time interrupt
            self.write(APIC_REG_TIMER_LOCAL_VECTOR, (1<<17) | 0x40);
        }
    }
}
<|endoftext|>