<commit_before>use std::cmp::Ordering;

use libimagstore::storeid::StoreId;
use libimagstore::store::Entry;
use libimagstore::store::EntryHeader;
use libimagstore::store::Result as StoreResult;

use error::{LinkError, LinkErrorKind};
use result::Result;

use toml::Value;
use itertools::Itertools;

pub type Link = StoreId;

pub trait InternalLinker {

    /// Get the internal links from the implementor object
    fn get_internal_links(&self) -> Result<Vec<Link>>;

    /// Set the internal links for the implementor object
    fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<Vec<Link>>;

    /// Add an internal link to the implementor object
    fn add_internal_link(&mut self, link: &mut Entry) -> Result<()>;

    /// Remove an internal link from the implementor object
    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()>;

}

impl InternalLinker for Entry {

    fn get_internal_links(&self) -> Result<Vec<Link>> {
        process_rw_result(self.get_header().read("imag.links"))
    }

    /// Set the links in a header and return the old links, if any.
    fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<Vec<Link>> {
        let self_location = self.get_location().clone();
        let mut new_links = vec![];

        for link in links {
            if let Err(e) = add_foreign_link(link, self_location.clone()) {
                return Err(e);
            }
            let link = link.get_location().clone();
            let link = link.to_str();
            if link.is_none() {
                return Err(LinkError::new(LinkErrorKind::InternalConversionError, None));
            }
            let link = link.unwrap();

            new_links.push(String::from(link));
        }

        let new_links = new_links
            .into_iter()
            .unique()
            .map(|s| Value::String(s))
            .sorted_by(|a, b| {
                match (a, b) {
                    (&Value::String(ref a), &Value::String(ref b)) => Ord::cmp(a, b),
                    _                                              => unreachable!()
                }
            });
        process_rw_result(self.get_header_mut().set("imag.links", Value::Array(new_links)))
    }

    fn add_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        let new_link = link.get_location().clone();

        add_foreign_link(link, self.get_location().clone())
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|mut links| {
                        links.push(new_link);
                        rewrite_links(self.get_header_mut(), links)
                    })
            })
    }

    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        let own_loc   = link.get_location().clone();
        let other_loc = link.get_location().clone();

        link.get_internal_links()
            .and_then(|links| {
                let links = links.into_iter().filter(|l| l.clone() != own_loc).collect();
                rewrite_links(self.get_header_mut(), links)
            })
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|links| {
                        let links = links.into_iter().filter(|l| l.clone() != other_loc).collect();
                        rewrite_links(link.get_header_mut(), links)
                    })
            })
    }

}

fn rewrite_links(header: &mut EntryHeader, links: Vec<StoreId>) -> Result<()> {
    let links : Vec<Option<Value>> = links
        .into_iter()
        .map(|s| s.to_str().map(|s| String::from(s)))
        .unique()
        .map(|elem| elem.map(|s| Value::String(s)))
        .sorted_by(|a, b| {
            match (a, b) {
                (&Some(Value::String(ref a)), &Some(Value::String(ref b))) => Ord::cmp(a, b),
                (&None, _) | (_, &None) => Ordering::Equal,
                _                                              => unreachable!()
            }
        });

    if links.iter().any(|o| o.is_none()) {
        // if any type convert failed we fail as well
        Err(LinkError::new(LinkErrorKind::InternalConversionError, None))
    } else {
        // I know it is ugly
        let links = links.into_iter().map(|opt| opt.unwrap()).collect();
        let process = header.set("imag.links", Value::Array(links));
        process_rw_result(process).map(|_| ())
    }
}

/// When Linking A -> B, the specification wants us to link back B -> A.
/// This is a helper function which does this.
fn add_foreign_link(target: &mut Entry, from: StoreId) -> Result<()> {
    target.get_internal_links()
        .and_then(|mut links| {
            links.push(from);
            let links : Vec<Option<Value>> = links
                .into_iter()
                .map(|s| {
                    match s.to_str() {
                        Some(s) => Some(String::from(s)),
                        _ => None
                    }
                })
                .unique()
                .map(|elem| elem.map(|s| Value::String(s)))
                .sorted_by(|a, b| {
                    match (a, b) {
                        (&Some(Value::String(ref a)), &Some(Value::String(ref b))) => Ord::cmp(a, b),
                        (&None, _) | (_, &None) => Ordering::Equal,
                        _                                              => unreachable!()
                    }
                });
            if links.iter().any(|o| o.is_none()) {
                Err(LinkError::new(LinkErrorKind::InternalConversionError, None))
            } else {
                let links = links.into_iter().map(|opt| opt.unwrap()).collect();
                process_rw_result(target.get_header_mut().set("imag.links", Value::Array(links)))
                    .map(|_| ())
            }
        })
}

fn process_rw_result(links: StoreResult<Option<Value>>) -> Result<Vec<Link>> {
    if links.is_err() {
        debug!("RW action on store failed. Generating LinkError");
        let lerr  = LinkError::new(LinkErrorKind::EntryHeaderReadError,
                                   Some(Box::new(links.err().unwrap())));
        return Err(lerr);
    }
    let links = links.unwrap();

    if links.is_none() {
        debug!("We got no value from the header!");
        return Ok(vec![])
    }
    let links = links.unwrap();

    let links = {
        match links {
            Value::Array(a) => a,
            _ => {
                debug!("We expected an Array for the links, but there was a non-Array!");
                return Err(LinkError::new(LinkErrorKind::ExistingLinkTypeWrong, None));
            },
        }
    };

    if !links.iter().all(|l| match l { &Value::String(_) => true, _ => false }) {
        debug!("At least one of the Values which were expected in the Array of links is a non-String!");
        debug!("Generating LinkError");
        return Err(LinkError::new(LinkErrorKind::ExistingLinkTypeWrong, None));
    }

    let links : Vec<Link> = links.into_iter()
        .map(|link| {
            match link {
                Value::String(s) => StoreId::from(s),
                _ => unreachable!(),
            }
        })
        .collect();

    debug!("Ok, the RW action was successful, returning link vector now!");
    Ok(links)
}

<commit_msg>Refactor: Use helper for type conversions instead of doing everything three times<commit_after>use std::cmp::Ordering;

use libimagstore::storeid::StoreId;
use libimagstore::store::Entry;
use libimagstore::store::EntryHeader;
use libimagstore::store::Result as StoreResult;

use error::{LinkError, LinkErrorKind};
use result::Result;

use toml::Value;
use itertools::Itertools;

pub type Link = StoreId;

pub trait InternalLinker {

    /// Get the internal links from the implementor object
    fn get_internal_links(&self) -> Result<Vec<Link>>;

    /// Set the internal links for the implementor object
    fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<Vec<Link>>;

    /// Add an internal link to the implementor object
    fn add_internal_link(&mut self, link: &mut Entry) -> Result<()>;

    /// Remove an internal link from the implementor object
    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()>;

}

impl InternalLinker for Entry {

    fn get_internal_links(&self) -> Result<Vec<Link>> {
        process_rw_result(self.get_header().read("imag.links"))
    }

    /// Set the links in a header and return the old links, if any.
    fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<Vec<Link>> {
        let self_location = self.get_location().clone();
        let mut new_links = vec![];

        for link in links {
            if let Err(e) = add_foreign_link(link, self_location.clone()) {
                return Err(e);
            }
            let link = link.get_location().clone();
            new_links.push(link);
        }

        let new_links = links_into_values(new_links);
        if new_links.iter().any(|o| o.is_none()) {
            return Err(LinkError::new(LinkErrorKind::InternalConversionError, None));
        }
        let new_links = new_links.into_iter().map(|o| o.unwrap()).collect();
        process_rw_result(self.get_header_mut().set("imag.links", Value::Array(new_links)))
    }

    fn add_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        let new_link = link.get_location().clone();

        add_foreign_link(link, self.get_location().clone())
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|mut links| {
                        links.push(new_link);
                        rewrite_links(self.get_header_mut(), links)
                    })
            })
    }

    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        let own_loc   = link.get_location().clone();
        let other_loc = link.get_location().clone();

        link.get_internal_links()
            .and_then(|links| {
                let links = links.into_iter().filter(|l| l.clone() != own_loc).collect();
                rewrite_links(self.get_header_mut(), links)
            })
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|links| {
                        let links = links.into_iter().filter(|l| l.clone() != other_loc).collect();
                        rewrite_links(link.get_header_mut(), links)
                    })
            })
    }

}

fn links_into_values(links: Vec<StoreId>) -> Vec<Option<Value>> {
    links
        .into_iter()
        .map(|s| s.to_str().map(|s| String::from(s)))
        .unique()
        .map(|elem| elem.map(|s| Value::String(s)))
        .sorted_by(|a, b| {
            match (a, b) {
                (&Some(Value::String(ref a)), &Some(Value::String(ref b))) => Ord::cmp(a, b),
                (&None, _) | (_, &None) => Ordering::Equal,
                _                                              => unreachable!()
            }
        })
}

fn rewrite_links(header: &mut EntryHeader, links: Vec<StoreId>) -> Result<()> {
    let links = links_into_values(links);

    if links.iter().any(|o| o.is_none()) {
        // if any type convert failed we fail as well
        Err(LinkError::new(LinkErrorKind::InternalConversionError, None))
    } else {
        // I know it is ugly
        let links = links.into_iter().map(|opt| opt.unwrap()).collect();
        let process = header.set("imag.links", Value::Array(links));
        process_rw_result(process).map(|_| ())
    }
}

/// When Linking A -> B, the specification wants us to link back B -> A.
/// This is a helper function which does this.
fn add_foreign_link(target: &mut Entry, from: StoreId) -> Result<()> {
    target.get_internal_links()
        .and_then(|mut links| {
            links.push(from);
            let links = links_into_values(links);
            if links.iter().any(|o| o.is_none()) {
                Err(LinkError::new(LinkErrorKind::InternalConversionError, None))
            } else {
                let links = links.into_iter().map(|opt| opt.unwrap()).collect();
                process_rw_result(target.get_header_mut().set("imag.links", Value::Array(links)))
                    .map(|_| ())
            }
        })
}

fn process_rw_result(links: StoreResult<Option<Value>>) -> Result<Vec<Link>> {
    if links.is_err() {
        debug!("RW action on store failed. Generating LinkError");
        let lerr  = LinkError::new(LinkErrorKind::EntryHeaderReadError,
                                   Some(Box::new(links.err().unwrap())));
        return Err(lerr);
    }
    let links = links.unwrap();

    if links.is_none() {
        debug!("We got no value from the header!");
        return Ok(vec![])
    }
    let links = links.unwrap();

    let links = {
        match links {
            Value::Array(a) => a,
            _ => {
                debug!("We expected an Array for the links, but there was a non-Array!");
                return Err(LinkError::new(LinkErrorKind::ExistingLinkTypeWrong, None));
            },
        }
    };

    if !links.iter().all(|l| match l { &Value::String(_) => true, _ => false }) {
        debug!("At least one of the Values which were expected in the Array of links is a non-String!");
        debug!("Generating LinkError");
        return Err(LinkError::new(LinkErrorKind::ExistingLinkTypeWrong, None));
    }

    let links : Vec<Link> = links.into_iter()
        .map(|link| {
            match link {
                Value::String(s) => StoreId::from(s),
                _ => unreachable!(),
            }
        })
        .collect();

    debug!("Ok, the RW action was successful, returning link vector now!");
    Ok(links)
}

<|endoftext|>


<commit_before>use cxx_gen::Opt;
use quote::quote;

#[test]
fn test_positive() {
    let rs = quote! {
        #[cxx::bridge]
        mod ffi {
            extern "C" {
                fn in_C();
            }
            extern "Rust" {
                fn in_rs();
            }
        }
    };
    let opt = Opt::default();
    let code = cxx_gen::generate_header_and_cc(rs, &opt).unwrap();
    assert!(code.header.len() > 0);
    assert!(code.implementation.len() > 0);
}

#[test]
fn test_negative() {
    let rs = quote! {};
    let opt = Opt::default();
    assert!(cxx_gen::generate_header_and_cc(rs, &opt).is_err())
}
<commit_msg>Resolve len_zero lint in cxx-gen test suite<commit_after>use cxx_gen::Opt;
use quote::quote;

#[test]
fn test_positive() {
    let rs = quote! {
        #[cxx::bridge]
        mod ffi {
            extern "C" {
                fn in_C();
            }
            extern "Rust" {
                fn in_rs();
            }
        }
    };
    let opt = Opt::default();
    let code = cxx_gen::generate_header_and_cc(rs, &opt).unwrap();
    assert!(!code.header.is_empty());
    assert!(!code.implementation.is_empty());
}

#[test]
fn test_negative() {
    let rs = quote! {};
    let opt = Opt::default();
    assert!(cxx_gen::generate_header_and_cc(rs, &opt).is_err())
}
<|endoftext|>


<commit_before>
extern mod sax;

use self::sax::*;

pub struct Registry {
    enum_nss: ~[EnumNs],
    cmd_nss: ~[CmdNs],
}

impl Registry {
    pub fn from_xml(data: &str) -> Registry {
        RegistryBuilder::parse(data)
    }
}

pub struct EnumNs {
    namespace: ~str,
    group: Option<~str>,
    ty: Option<~str>,
    start: Option<~str>,
    end: Option<~str>,
    vendor: Option<~str>,
    comment: Option<~str>,
    enums: ~[Enum],
}

pub struct Enum {
    ident: ~str,
    value: ~str,
}

pub struct CmdNs {
    namespace: ~str,
    cmds: ~[Cmd],
}

pub struct Binding {
    ident: ~str,
    ty: ~str,
}

pub struct Cmd {
    proto: Binding,
    params: ~[Binding],
    alias: Option<~str>,
    vecequiv: Option<~str>,
    glx: Option<GlxOpcode>,
}

pub struct GlxOpcode {
    ty: ~str,
    opcode: ~str,
    name: Option<~str>,
    comment: Option<~str>,
}

struct RegistryBuilder {
    priv port: SaxPort,
}

impl<'self> RegistryBuilder {
    fn recv(&self) -> ParseEvent {
        loop {
            match self.port.recv() {
                Ok(StartDocument) => (),
                Ok(Comment(_)) => (),
                Ok(Characters(ref ch)) if ch.is_whitespace() => (),
                Ok(EndDocument) => fail!("The end of the document has been reached"),
                Ok(event) => return event,
                Err(err) => fail!("XML error: %s", err.to_str()),
            }
        }
    }

    fn parse(data: &str) -> Registry {
        RegistryBuilder {
            port: parse_xml(data)
        }.consume_registry()
    }

    fn expect_characters(&self) -> ~str {
        match self.recv() {
            Characters(ref ch) => ch.clone(),
            msg => fail!("Expected characters, found: %s", msg.to_str()),
        }
    }

    fn expect_start_element(&self, name: &str) -> Attributes {
        match self.recv() {
            StartElement(ref n, ref atts) if name == *n => atts.clone(),
            msg => fail!("Expected <%s>, found: %s", name, msg.to_str()),
        }
    }

    fn expect_end_element(&self, name: &str) {
        match self.recv() {
            EndElement(ref n) if name == *n => (),
            msg => fail!("Expected </%s>, found: %s", name, msg.to_str()),
        }
    }

    fn skip_until(&self, event: ParseEvent) {
        loop {
            let msg = self.recv();
            if msg == event || msg == EndDocument { break }
        }
    }

    fn consume_registry(&self) -> Registry {
        self.expect_start_element("registry");
        let mut registry = Registry { enum_nss: ~[], cmd_nss: ~[] };
        loop {
            match self.recv() {
                // ignores
                Characters(_) | Comment(_) => (),
                StartElement(~"comment", _) => self.skip_until(EndElement(~"comment")),
                StartElement(~"types", _) => self.skip_until(EndElement(~"types")),
                StartElement(~"groups", _) => self.skip_until(EndElement(~"groups")),
                StartElement(~"feature", _) => self.skip_until(EndElement(~"feature")),
                StartElement(~"extensions", _) => self.skip_until(EndElement(~"extensions")),

                // add enum namespace
                StartElement(~"enums", ref atts) => {
                    registry.enum_nss.push(
                        EnumNs {
                            namespace:  atts.get_copy(&~"namespace"),
                            group:      atts.find_copy(&~"group"),
                            ty:         atts.find_copy(&~"type"),
                            start:      atts.find_copy(&~"start"),
                            end:        atts.find_copy(&~"end"),
                            vendor:     atts.find_copy(&~"vendor"),
                            comment:    atts.find_copy(&~"comment"),
                            enums:      self.consume_enums(),
                        }
                    )
                }

                // add command namespace
                StartElement(~"commands", ref atts) => {
                    registry.cmd_nss.push(
                        CmdNs {
                            namespace:  atts.get_copy(&~"namespace"),
                            cmds:       self.consume_cmds(),
                        }
                    );
                }

                // finished building the registry
                EndElement(~"registry") => break,

                // error handling
                msg => fail!("Expected </registry>, found: %s", msg.to_str()),
            }
        }
        registry
    }

    fn consume_enums(&self) -> ~[Enum] {
        let mut enums = ~[];
        loop {
            match self.recv() {
                // ignores
                Characters(_) | Comment(_) => (),
                StartElement(~"unused", _) => self.skip_until(EndElement(~"unused")),

                // add enum definition
                StartElement(~"enum", ref atts) => {
                    enums.push(
                        Enum {
                            ident:  atts.get_copy(&~"name"),
                            value:  atts.get_copy(&~"value"),
                        }
                    );
                    self.expect_end_element("enum");
                }

                // finished building the namespace
                EndElement(~"enums") => break,
                // error handling
                msg => fail!("Expected </enums>, found: %s", msg.to_str()),
            }
        }
        enums
    }

    fn consume_cmds(&self) -> ~[Cmd] {
        let mut cmds = ~[];
        loop {
            match self.recv() {
                // add command definition
                StartElement(~"command", _) => {
                    cmds.push(self.consume_cmd());
                }
                // finished building the namespace
                EndElement(~"commands") => break,
                // error handling
                msg => fail!("Expected </commands>, found: %s", msg.to_str()),
            }
        }
        cmds
    }

    fn consume_cmd(&self) -> Cmd {
        // consume command prototype
        self.expect_start_element("proto");
        let proto = self.consume_binding();
        self.expect_end_element("proto");

        let mut params = ~[];
        let mut alias = None;
        let mut vecequiv = None;
        let mut glx = None;

        loop {
            match self.recv() {
                StartElement(~"param", _) => {
                    params.push(
                        self.consume_binding()
                    );
                    self.expect_end_element("param");
                }
                StartElement(~"alias", ref atts) => {
                    alias = atts.find_copy(&~"alias");
                    self.expect_end_element("alias");
                }
                StartElement(~"vecequiv", ref atts) => {
                    vecequiv = atts.find_copy(&~"vecequiv");
                    self.expect_end_element("vecequiv");
                }
                StartElement(~"glx", ref atts) => {
                    glx = Some(GlxOpcode {
                        ty:      atts.get_copy(&~"type"),
                        opcode:  atts.get_copy(&~"opcode"),
                        name:    atts.find_copy(&~"name"),
                        comment: atts.find_copy(&~"comment"),
                    });
                    self.expect_end_element("glx");
                }
                EndElement(~"command") => break,
                msg => fail!("Expected </command>, found: %s", msg.to_str()),
            }
        }
        Cmd {
            proto: proto,
            params: params,
            alias: alias,
            vecequiv: vecequiv,
            glx: glx,
        }
    }

    fn consume_binding(&self) -> Binding {
        // consume type
        let mut ty = ~"";
        loop {
            match self.recv() {
                Characters(ch) => ty.push_str(ch),
                StartElement(~"ptype", _) => (),
                EndElement(~"ptype") => (),
                StartElement(~"name", _) => break,
                msg => fail!("Expected binding, found: %s", msg.to_str()),
            }
        }
        let ident = self.expect_characters();
        // consume identifier
        self.expect_end_element("name");
        Binding {
            ident: ident,
            ty: ty,
        }
    }
}
<commit_msg>Update to the latest sax-rs<commit_after>
extern mod sax;

use self::sax::*;

pub struct Registry {
    enum_nss: ~[EnumNs],
    cmd_nss: ~[CmdNs],
}

impl Registry {
    pub fn from_xml(data: &str) -> Registry {
        RegistryBuilder::parse(data)
    }
}

pub struct EnumNs {
    namespace: ~str,
    group: Option<~str>,
    ty: Option<~str>,
    start: Option<~str>,
    end: Option<~str>,
    vendor: Option<~str>,
    comment: Option<~str>,
    enums: ~[Enum],
}

pub struct Enum {
    ident: ~str,
    value: ~str,
}

pub struct CmdNs {
    namespace: ~str,
    cmds: ~[Cmd],
}

pub struct Binding {
    ident: ~str,
    ty: ~str,
}

pub struct Cmd {
    proto: Binding,
    params: ~[Binding],
    alias: Option<~str>,
    vecequiv: Option<~str>,
    glx: Option<GlxOpcode>,
}

pub struct GlxOpcode {
    ty: ~str,
    opcode: ~str,
    name: Option<~str>,
    comment: Option<~str>,
}

struct RegistryBuilder {
    priv port: SaxPort,
}

impl<'self> RegistryBuilder {
    fn parse(data: &str) -> Registry {
        RegistryBuilder {
            port: parse_xml(data)
        }.consume_registry()
    }

    fn recv(&self) -> ParseEvent {
        loop {
            match self.port.recv() {
                Ok(StartDocument) => (),
                Ok(Comment(_)) => (),
                Ok(Characters(ref ch)) if ch.is_whitespace() => (),
                Ok(EndDocument) => fail!("The end of the document has been reached"),
                Ok(event) => return event,
                Err(err) => fail!("XML error: %s", err.to_str()),
            }
        }
    }

    fn expect_characters(&self) -> ~str {
        match self.recv() {
            Characters(ref ch) => ch.clone(),
            msg => fail!("Expected characters, found: %s", msg.to_str()),
        }
    }

    fn expect_start_element(&self, name: &str) -> Attributes {
        match self.recv() {
            StartElement(ref n, ref atts) if name == *n => atts.clone(),
            msg => fail!("Expected <%s>, found: %s", name, msg.to_str()),
        }
    }

    fn expect_end_element(&self, name: &str) {
        match self.recv() {
            EndElement(ref n) if name == *n => (),
            msg => fail!("Expected </%s>, found: %s", name, msg.to_str()),
        }
    }

    fn skip_until(&self, event: ParseEvent) {
        loop {
            let msg = self.recv();
            if msg == event || msg == EndDocument { break }
        }
    }

    fn consume_registry(&self) -> Registry {
        self.expect_start_element("registry");
        let mut registry = Registry { enum_nss: ~[], cmd_nss: ~[] };
        loop {
            match self.recv() {
                // ignores
                Characters(_) | Comment(_) => (),
                StartElement(~"comment", _) => self.skip_until(EndElement(~"comment")),
                StartElement(~"types", _) => self.skip_until(EndElement(~"types")),
                StartElement(~"groups", _) => self.skip_until(EndElement(~"groups")),
                StartElement(~"feature", _) => self.skip_until(EndElement(~"feature")),
                StartElement(~"extensions", _) => self.skip_until(EndElement(~"extensions")),

                // add enum namespace
                StartElement(~"enums", ref atts) => {
                    registry.enum_nss.push(
                        EnumNs {
                            namespace:  atts.get_clone("namespace"),
                            group:      atts.find_clone("group"),
                            ty:         atts.find_clone("type"),
                            start:      atts.find_clone("start"),
                            end:        atts.find_clone("end"),
                            vendor:     atts.find_clone("vendor"),
                            comment:    atts.find_clone("comment"),
                            enums:      self.consume_enums(),
                        }
                    )
                }

                // add command namespace
                StartElement(~"commands", ref atts) => {
                    registry.cmd_nss.push(
                        CmdNs {
                            namespace:  atts.get_clone("namespace"),
                            cmds:       self.consume_cmds(),
                        }
                    );
                }

                // finished building the registry
                EndElement(~"registry") => break,

                // error handling
                msg => fail!("Expected </registry>, found: %s", msg.to_str()),
            }
        }
        registry
    }

    fn consume_enums(&self) -> ~[Enum] {
        let mut enums = ~[];
        loop {
            match self.recv() {
                // ignores
                Characters(_) | Comment(_) => (),
                StartElement(~"unused", _) => self.skip_until(EndElement(~"unused")),

                // add enum definition
                StartElement(~"enum", ref atts) => {
                    enums.push(
                        Enum {
                            ident:  atts.get_clone("name"),
                            value:  atts.get_clone("value"),
                        }
                    );
                    self.expect_end_element("enum");
                }

                // finished building the namespace
                EndElement(~"enums") => break,
                // error handling
                msg => fail!("Expected </enums>, found: %s", msg.to_str()),
            }
        }
        enums
    }

    fn consume_cmds(&self) -> ~[Cmd] {
        let mut cmds = ~[];
        loop {
            match self.recv() {
                // add command definition
                StartElement(~"command", _) => {
                    cmds.push(self.consume_cmd());
                }
                // finished building the namespace
                EndElement(~"commands") => break,
                // error handling
                msg => fail!("Expected </commands>, found: %s", msg.to_str()),
            }
        }
        cmds
    }

    fn consume_cmd(&self) -> Cmd {
        // consume command prototype
        self.expect_start_element("proto");
        let proto = self.consume_binding();
        self.expect_end_element("proto");

        let mut params = ~[];
        let mut alias = None;
        let mut vecequiv = None;
        let mut glx = None;
        loop {
            match self.recv() {
                StartElement(~"param", _) => {
                    params.push(
                        self.consume_binding()
                    );
                    self.expect_end_element("param");
                }
                StartElement(~"alias", ref atts) => {
                    alias = atts.find_clone("alias");
                    self.expect_end_element("alias");
                }
                StartElement(~"vecequiv", ref atts) => {
                    vecequiv = atts.find_clone("vecequiv");
                    self.expect_end_element("vecequiv");
                }
                StartElement(~"glx", ref atts) => {
                    glx = Some(GlxOpcode {
                        ty:      atts.get_clone("type"),
                        opcode:  atts.get_clone("opcode"),
                        name:    atts.find_clone("name"),
                        comment: atts.find_clone("comment"),
                    });
                    self.expect_end_element("glx");
                }
                EndElement(~"command") => break,
                msg => fail!("Expected </command>, found: %s", msg.to_str()),
            }
        }

        Cmd {
            proto: proto,
            params: params,
            alias: alias,
            vecequiv: vecequiv,
            glx: glx,
        }
    }

    fn consume_binding(&self) -> Binding {
        // consume type
        let mut ty = ~"";
        loop {
            match self.recv() {
                Characters(ch) => ty.push_str(ch),
                StartElement(~"ptype", _) => (),
                EndElement(~"ptype") => (),
                StartElement(~"name", _) => break,
                msg => fail!("Expected binding, found: %s", msg.to_str()),
            }
        }
        // consume identifier
        let ident = self.expect_characters();
        self.expect_end_element("name");
        Binding {
            ident: ident,
            ty: ty,
        }
    }
}
<|endoftext|>


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

use std::rc::*;
use std::cell::*;

use super::super::util::clonecell::*;
use super::super::tree::*;

use super::component::*;

struct Subscription<TData: Clone> {
    callback: RefCell<ConsumerCallback>,
    data: TData
}

type SubscriptionRef<TData> = Rc<Subscription<TData>>;

///
/// The subscription manager is an interior mutable type that can store subscriptions created from consumers.
/// The principle use case is to make it so that publishers and consumers can share a list of subscriptions.
///
pub struct SubscriptionManager<TData: Clone> {
    subscriptions: CloneCell<Vec<SubscriptionRef<TData>>>
}

impl<TData: Clone> SubscriptionManager<TData> {
    ///
    /// Creates a new subscription manager
    ///
    pub fn new() -> SubscriptionManager<TData> {
        SubscriptionManager { subscriptions: CloneCell::new(vec![]) }
    }

    ///
    /// Modifies this subscription manager to add the specified subscription
    ///
    pub fn add_subscription(&self, callback_data: TData, callback: ConsumerCallback) {
        // Turn the callback into a reference
        let new_callback = Rc::new(Subscription { callback: RefCell::new(callback), data: callback_data });

        // Retrieve and update the subscriptions
        let mut subscriptions = self.subscriptions.get();
        subscriptions.push(new_callback);
        self.subscriptions.set(subscriptions);
    }

    ///
    /// Calls the subscriptions matching a particular filter
    ///
    pub fn call_subscriptions(&self, call_filter: &Fn(&TData) -> bool, change: &TreeChange) {
        // Retrieve the active subscriptions
        let subscriptions = self.subscriptions.get();

        // Call any subscription matching the filter
        for possible_subscription in subscriptions {
            if call_filter(&possible_subscription.data) {
                let mut callback: RefMut<ConsumerCallback> = possible_subscription.callback.borrow_mut();
                callback(change);
            }
        }
    }
}

#[cfg(test)]
mod subscriptionmanager_tests {
    use std::rc::*;
    use std::cell::*;

    use super::*;
    use super::super::super::tree::*;

    #[test]
    pub fn can_call_subscription() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"".to_tree_node()));

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));

        // Call the subscription a few times (result should update)
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 1);
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 2);
    }

    #[test]
    pub fn can_filter_all_subscriptions() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"".to_tree_node()));

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));

        // Call the subscription a few times (result should not update)
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 0);
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 0);
    }

    #[test]
    pub fn can_filter_some_subscriptions() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"".to_tree_node()));

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();
        let callback_count2 = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));
        manager.add_subscription(1, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count2.get();
            let new_value   = count_value + 1;
            callback_count2.set(new_value);
        }));

        // Call the subscription a few times (result should not update)
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 2);
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 2);
        manager.call_subscriptions(&|data| { *data == 1 }, &a_change);
        assert!(change_count.get() == 3);
    }
}
<commit_msg>Work around issue with putting boxed FnMuts in RefCells with a structure that does the thing that rust can't.<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

use std::rc::*;
use std::cell::*;

use super::super::util::clonecell::*;
use super::super::tree::*;

use super::component::*;

struct Subscription<TData: Clone> {
    callback: RefCell<SubscriptionCallback>,
    data: TData
}

type SubscriptionRef<TData> = Rc<Subscription<TData>>;

///
/// SubscriptionCallback gets around an issue with RefCell.
///
/// If we do RefCell<Box<Fn>> we can't do .borrow_mut()() because the borrow checker treats the box as immutable
/// for reasons that seem counter-intuitive.
///
struct SubscriptionCallback {
    callback: ConsumerCallback
}

impl SubscriptionCallback {
    #[inline]
    fn run_callback(&mut self, change: &TreeChange) {
        let ref mut callback = self.callback;
        callback(change);
    }
}

///
/// The subscription manager is an interior mutable type that can store subscriptions created from consumers.
/// The principle use case is to make it so that publishers and consumers can share a list of subscriptions.
///
pub struct SubscriptionManager<TData: Clone> {
    subscriptions: CloneCell<Vec<SubscriptionRef<TData>>>
}

impl<TData: Clone> SubscriptionManager<TData> {
    ///
    /// Creates a new subscription manager
    ///
    pub fn new() -> SubscriptionManager<TData> {
        SubscriptionManager { subscriptions: CloneCell::new(vec![]) }
    }

    ///
    /// Modifies this subscription manager to add the specified subscription
    ///
    pub fn add_subscription(&self, callback_data: TData, callback: ConsumerCallback) {
        // Turn the callback into a reference
        let new_callback = Rc::new(Subscription { callback: RefCell::new(SubscriptionCallback { callback: callback }), data: callback_data });

        // Retrieve and update the subscriptions
        let mut subscriptions = self.subscriptions.get();
        subscriptions.push(new_callback);
        self.subscriptions.set(subscriptions);
    }

    ///
    /// Calls the subscriptions matching a particular filter
    ///
    pub fn call_subscriptions(&self, call_filter: &Fn(&TData) -> bool, change: &TreeChange) {
        // Retrieve the active subscriptions
        let subscriptions = self.subscriptions.get();

        // Call any subscription matching the filter
        for possible_subscription in subscriptions {
            if call_filter(&possible_subscription.data) {
                let mut callback = possible_subscription.callback.borrow_mut();
                callback.run_callback(change);
            }
        }
    }
}

#[cfg(test)]
mod subscriptionmanager_tests {
    use std::rc::*;
    use std::cell::*;

    use super::*;
    use super::super::super::tree::*;

    #[test]
    pub fn can_call_subscription() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"".to_tree_node()));

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));

        // Call the subscription a few times (result should update)
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 1);
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 2);
    }

    #[test]
    pub fn can_filter_all_subscriptions() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"".to_tree_node()));

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));

        // Call the subscription a few times (result should not update)
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 0);
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 0);
    }

    #[test]
    pub fn can_filter_some_subscriptions() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"".to_tree_node()));

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();
        let callback_count2 = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));
        manager.add_subscription(1, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count2.get();
            let new_value   = count_value + 1;
            callback_count2.set(new_value);
        }));

        // Call the subscription a few times (result should not update)
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 2);
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 2);
        manager.call_subscriptions(&|data| { *data == 1 }, &a_change);
        assert!(change_count.get() == 3);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Gilad Naaman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/// Macro to create a local `base_ptr` raw pointer of the given type, avoiding UB as
/// much as is possible currently.
#[cfg(maybe_uninit)]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__let_base_ptr {
    ($name:ident, $type:ty) => {
        // No UB here, and the pointer does not dangle, either.
        // But we have to make sure that `uninit` lives long enough,
        // so it has to be in the same scope as `$name`. That's why
        // `let_base_ptr` declares a variable (several, actually)
        // instead of returning one.
        let uninit = $crate::__priv::mem::MaybeUninit::<$type>::uninit();
        let $name: *const $type = uninit.as_ptr();
    };
}
#[cfg(not(maybe_uninit))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__let_base_ptr {
    ($name:ident, $type:ty) => {
        // No UB right here, but we will later dereference this pointer to
        // offset into a field, and that is UB because the pointer is dangling.
        let $name = $crate::__priv::mem::align_of::<$type>() as *const $type;
    };
}

/// Macro to compute the distance between two pointers.
#[cfg(feature = "unstable_const")]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset_offset_from_unsafe {
    ($field:expr, $base:expr) => {{
        let field = $field; // evaluate $field outside the `unsafe` block
        let base = $base; // evaluate $base outside the `unsafe` block
        // Compute offset, with unstable `offset_from` for const-compatibility.
        // (Requires the pointers to not dangle, but we already need that for `raw_field!` anyway.)
        unsafe { (field as *const u8).offset_from(base as *const u8) as usize }
    }};
}
#[cfg(not(feature = "unstable_const"))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset_offset_from_unsafe {
    ($field:expr, $base:expr) => {
        // Compute offset.
        ($field as usize) - ($base as usize)
    };
}

/// Calculates the offset of the specified field from the start of the named struct.
///
/// ## Examples
/// ```
/// use memoffset::offset_of;
///
/// #[repr(C, packed)]
/// struct Foo {
///     a: u32,
///     b: u64,
///     c: [u8; 5]
/// }
///
/// fn main() {
///     assert_eq!(offset_of!(Foo, a), 0);
///     assert_eq!(offset_of!(Foo, b), 4);
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! offset_of {
    ($parent:path, $field:tt) => {{
        // Get a base pointer (non-dangling if rustc supports `MaybeUninit`).
        _memoffset__let_base_ptr!(base_ptr, $parent);
        // Get field pointer.
        let field_ptr = raw_field!(base_ptr, $parent, $field);
        // Compute offset.
        _memoffset_offset_from_unsafe!(field_ptr, base_ptr)
    }};
}

/// Calculates the offset of the specified field from the start of the tuple.
///
/// ## Examples
/// ```
/// use memoffset::offset_of_tuple;
///
/// fn main() {
///     assert!(offset_of_tuple!((u8, u32), 1) >= 0, "Tuples do not have a defined layout");
/// }
/// ```
#[cfg(tuple_ty)]
#[macro_export(local_inner_macros)]
macro_rules! offset_of_tuple {
    ($parent:ty, $field:tt) => {{
        // Get a base pointer (non-dangling if rustc supports `MaybeUninit`).
        _memoffset__let_base_ptr!(base_ptr, $parent);
        // Get field pointer.
        let field_ptr = raw_field_tuple!(base_ptr, $parent, $field);
        // Compute offset.
        _memoffset_offset_from_unsafe!(field_ptr, base_ptr)
    }};
}

/// Calculates the offset of the specified union member from the start of the union.
///
/// ## Examples
/// ```
/// use memoffset::offset_of_union;
///
/// #[repr(C, packed)]
/// union Foo {
///     foo32: i32,
///     foo64: i64,
/// }
///
/// fn main() {
///     assert!(offset_of_union!(Foo, foo64) == 0);
/// }
/// ```
///
/// ## Note
/// Due to macro_rules limitations, this check will accept structs with a single field as well as unions.
/// Using this macro for a single-field struct will still work, but might lead to a future
/// compatibility problem if the struct gains more fields.
#[macro_export(local_inner_macros)]
macro_rules! offset_of_union {
    ($parent:path, $field:tt) => {{
        // Get a base pointer (non-dangling if rustc supports `MaybeUninit`).
        _memoffset__let_base_ptr!(base_ptr, $parent);
        // Get field pointer.
        let field_ptr = raw_field_union!(base_ptr, $parent, $field);
        // Compute offset.
        _memoffset_offset_from_unsafe!(field_ptr, base_ptr)
    }};
}

#[cfg(test)]
mod tests {
    #[test]
    fn offset_simple() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 8);
    }

    #[test]
    #[cfg_attr(miri, ignore)] // this creates unaligned references
    fn offset_simple_packed() {
        #[repr(C, packed)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 6);
    }

    #[test]
    fn tuple_struct() {
        #[repr(C)]
        struct Tup(i32, i32);

        assert_eq!(offset_of!(Tup, 0), 0);
        assert_eq!(offset_of!(Tup, 1), 4);
    }

    #[test]
    fn offset_union() {
        // Since we're specifying repr(C), all fields are supposed to be at offset 0
        #[repr(C)]
        union Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of_union!(Foo, a), 0);
        assert_eq!(offset_of_union!(Foo, b), 0);
        assert_eq!(offset_of_union!(Foo, c), 0);
    }

    #[test]
    fn path() {
        mod sub {
            #[repr(C)]
            pub struct Foo {
                pub x: u32,
            }
        }

        assert_eq!(offset_of!(sub::Foo, x), 0);
    }

    #[test]
    fn inside_generic_method() {
        struct Pair<T, U>(T, U);

        fn foo<T, U>(_: Pair<T, U>) -> usize {
            offset_of!(Pair<T, U>, 1)
        }

        assert_eq!(foo(Pair(0, 0)), 4);
    }

    #[cfg(tuple_ty)]
    #[test]
    fn test_tuple_offset() {
        let f = (0i32, 0.0f32, 0u8);
        let f_ptr = &f as *const _;
        let f1_ptr = &f.1 as *const _;

        assert_eq!(
            f1_ptr as usize - f_ptr as usize,
            offset_of_tuple!((i32, f32, u8), 1)
        );
    }

    #[test]
    fn test_raw_field() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        let f: Foo = Foo {
            a: 0,
            b: [0, 0],
            c: 0,
        };
        let f_ptr = &f as *const _;
        assert_eq!(f_ptr as usize + 0, raw_field!(f_ptr, Foo, a) as usize);
        assert_eq!(f_ptr as usize + 4, raw_field!(f_ptr, Foo, b) as usize);
        assert_eq!(f_ptr as usize + 8, raw_field!(f_ptr, Foo, c) as usize);
    }

    #[cfg(tuple_ty)]
    #[test]
    fn test_raw_field_tuple() {
        let t = (0u32, 0u8, false);
        let t_ptr = &t as *const _;
        let t_addr = t_ptr as usize;

        assert_eq!(
            &t.0 as *const _ as usize - t_addr,
            raw_field_tuple!(t_ptr, (u32, u8, bool), 0) as usize - t_addr
        );
        assert_eq!(
            &t.1 as *const _ as usize - t_addr,
            raw_field_tuple!(t_ptr, (u32, u8, bool), 1) as usize - t_addr
        );
        assert_eq!(
            &t.2 as *const _ as usize - t_addr,
            raw_field_tuple!(t_ptr, (u32, u8, bool), 2) as usize - t_addr
        );
    }

    #[test]
    fn test_raw_field_union() {
        #[repr(C)]
        union Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        let f = Foo { a: 0 };
        let f_ptr = &f as *const _;
        assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, a) as usize);
        assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, b) as usize);
        assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, c) as usize);
    }

    #[cfg(feature = "unstable_const")]
    #[test]
    fn const_offset() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!([0; offset_of!(Foo, b)].len(), 4);
    }

    #[cfg(feature = "unstable_const")]
    #[test]
    fn const_offset_interior_mutable() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: core::cell::Cell<u32>,
        }

        assert_eq!([0; offset_of!(Foo, b)].len(), 4);
    }

    #[cfg(feature = "unstable_const")]
    #[test]
    fn const_fn_offset() {
        const fn test_fn() -> usize {
            #[repr(C)]
            struct Foo {
                a: u32,
                b: [u8; 2],
                c: i64,
            }

            offset_of!(Foo, b)
        }

        assert_eq!([0; test_fn()].len(), 4);
    }
}
<commit_msg>Update src/offset_of.rs<commit_after>// Copyright (c) 2017 Gilad Naaman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/// Macro to create a local `base_ptr` raw pointer of the given type, avoiding UB as
/// much as is possible currently.
#[cfg(maybe_uninit)]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__let_base_ptr {
    ($name:ident, $type:ty) => {
        // No UB here, and the pointer does not dangle, either.
        // But we have to make sure that `uninit` lives long enough,
        // so it has to be in the same scope as `$name`. That's why
        // `let_base_ptr` declares a variable (several, actually)
        // instead of returning one.
        let uninit = $crate::__priv::mem::MaybeUninit::<$type>::uninit();
        let $name: *const $type = uninit.as_ptr();
    };
}
#[cfg(not(maybe_uninit))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__let_base_ptr {
    ($name:ident, $type:ty) => {
        // No UB right here, but we will later dereference this pointer to
        // offset into a field, and that is UB because the pointer is dangling.
        let $name = $crate::__priv::mem::align_of::<$type>() as *const $type;
    };
}

/// Macro to compute the distance between two pointers.
#[cfg(feature = "unstable_const")]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset_offset_from_unsafe {
    ($field:expr, $base:expr) => {{
        let field = $field; // evaluate $field outside the `unsafe` block
        let base = $base; // evaluate $base outside the `unsafe` block
        // Compute offset, with unstable `offset_from` for const-compatibility.
        // (Requires the pointers to not dangle, but we already need that for `raw_field!` anyway.)
        unsafe { (field as *const u8).offset_from(base as *const u8) as usize }
    }};
}
#[cfg(not(feature = "unstable_const"))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset_offset_from_unsafe {
    ($field:expr, $base:expr) => {
        // Compute offset.
        ($field as usize) - ($base as usize)
    };
}

/// Calculates the offset of the specified field from the start of the named struct.
///
/// ## Examples
/// ```
/// use memoffset::offset_of;
///
/// #[repr(C, packed)]
/// struct Foo {
///     a: u32,
///     b: u64,
///     c: [u8; 5]
/// }
///
/// fn main() {
///     assert_eq!(offset_of!(Foo, a), 0);
///     assert_eq!(offset_of!(Foo, b), 4);
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! offset_of {
    ($parent:path, $field:tt) => {{
        // Get a base pointer (non-dangling if rustc supports `MaybeUninit`).
        _memoffset__let_base_ptr!(base_ptr, $parent);
        // Get field pointer.
        let field_ptr = raw_field!(base_ptr, $parent, $field);
        // Compute offset.
        _memoffset_offset_from_unsafe!(field_ptr, base_ptr)
    }};
}

/// Calculates the offset of the specified field from the start of the tuple.
///
/// ## Examples
/// ```
/// use memoffset::offset_of_tuple;
///
/// fn main() {
///     assert!(offset_of_tuple!((u8, u32), 1) >= 0, "Tuples do not have a defined layout");
/// }
/// ```
#[cfg(tuple_ty)]
#[macro_export(local_inner_macros)]
macro_rules! offset_of_tuple {
    ($parent:ty, $field:tt) => {{
        // Get a base pointer (non-dangling if rustc supports `MaybeUninit`).
        _memoffset__let_base_ptr!(base_ptr, $parent);
        // Get field pointer.
        let field_ptr = raw_field_tuple!(base_ptr, $parent, $field);
        // Compute offset.
        _memoffset_offset_from_unsafe!(field_ptr, base_ptr)
    }};
}

/// Calculates the offset of the specified union member from the start of the union.
///
/// ## Examples
/// ```
/// use memoffset::offset_of_union;
///
/// #[repr(C, packed)]
/// union Foo {
///     foo32: i32,
///     foo64: i64,
/// }
///
/// fn main() {
///     assert!(offset_of_union!(Foo, foo64) == 0);
/// }
/// ```
///
/// ## Note
/// Due to macro_rules limitations, this macro will accept structs with a single field as well as unions.
/// This is not a stable guarantee, and future versions of this crate might fail
/// on any use of this macro with a struct, without a semver bump.
#[macro_export(local_inner_macros)]
macro_rules! offset_of_union {
    ($parent:path, $field:tt) => {{
        // Get a base pointer (non-dangling if rustc supports `MaybeUninit`).
        _memoffset__let_base_ptr!(base_ptr, $parent);
        // Get field pointer.
        let field_ptr = raw_field_union!(base_ptr, $parent, $field);
        // Compute offset.
        _memoffset_offset_from_unsafe!(field_ptr, base_ptr)
    }};
}

#[cfg(test)]
mod tests {
    #[test]
    fn offset_simple() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 8);
    }

    #[test]
    #[cfg_attr(miri, ignore)] // this creates unaligned references
    fn offset_simple_packed() {
        #[repr(C, packed)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 6);
    }

    #[test]
    fn tuple_struct() {
        #[repr(C)]
        struct Tup(i32, i32);

        assert_eq!(offset_of!(Tup, 0), 0);
        assert_eq!(offset_of!(Tup, 1), 4);
    }

    #[test]
    fn offset_union() {
        // Since we're specifying repr(C), all fields are supposed to be at offset 0
        #[repr(C)]
        union Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of_union!(Foo, a), 0);
        assert_eq!(offset_of_union!(Foo, b), 0);
        assert_eq!(offset_of_union!(Foo, c), 0);
    }

    #[test]
    fn path() {
        mod sub {
            #[repr(C)]
            pub struct Foo {
                pub x: u32,
            }
        }

        assert_eq!(offset_of!(sub::Foo, x), 0);
    }

    #[test]
    fn inside_generic_method() {
        struct Pair<T, U>(T, U);

        fn foo<T, U>(_: Pair<T, U>) -> usize {
            offset_of!(Pair<T, U>, 1)
        }

        assert_eq!(foo(Pair(0, 0)), 4);
    }

    #[cfg(tuple_ty)]
    #[test]
    fn test_tuple_offset() {
        let f = (0i32, 0.0f32, 0u8);
        let f_ptr = &f as *const _;
        let f1_ptr = &f.1 as *const _;

        assert_eq!(
            f1_ptr as usize - f_ptr as usize,
            offset_of_tuple!((i32, f32, u8), 1)
        );
    }

    #[test]
    fn test_raw_field() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        let f: Foo = Foo {
            a: 0,
            b: [0, 0],
            c: 0,
        };
        let f_ptr = &f as *const _;
        assert_eq!(f_ptr as usize + 0, raw_field!(f_ptr, Foo, a) as usize);
        assert_eq!(f_ptr as usize + 4, raw_field!(f_ptr, Foo, b) as usize);
        assert_eq!(f_ptr as usize + 8, raw_field!(f_ptr, Foo, c) as usize);
    }

    #[cfg(tuple_ty)]
    #[test]
    fn test_raw_field_tuple() {
        let t = (0u32, 0u8, false);
        let t_ptr = &t as *const _;
        let t_addr = t_ptr as usize;

        assert_eq!(
            &t.0 as *const _ as usize - t_addr,
            raw_field_tuple!(t_ptr, (u32, u8, bool), 0) as usize - t_addr
        );
        assert_eq!(
            &t.1 as *const _ as usize - t_addr,
            raw_field_tuple!(t_ptr, (u32, u8, bool), 1) as usize - t_addr
        );
        assert_eq!(
            &t.2 as *const _ as usize - t_addr,
            raw_field_tuple!(t_ptr, (u32, u8, bool), 2) as usize - t_addr
        );
    }

    #[test]
    fn test_raw_field_union() {
        #[repr(C)]
        union Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        let f = Foo { a: 0 };
        let f_ptr = &f as *const _;
        assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, a) as usize);
        assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, b) as usize);
        assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, c) as usize);
    }

    #[cfg(feature = "unstable_const")]
    #[test]
    fn const_offset() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!([0; offset_of!(Foo, b)].len(), 4);
    }

    #[cfg(feature = "unstable_const")]
    #[test]
    fn const_offset_interior_mutable() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: core::cell::Cell<u32>,
        }

        assert_eq!([0; offset_of!(Foo, b)].len(), 4);
    }

    #[cfg(feature = "unstable_const")]
    #[test]
    fn const_fn_offset() {
        const fn test_fn() -> usize {
            #[repr(C)]
            struct Foo {
                a: u32,
                b: [u8; 2],
                c: i64,
            }

            offset_of!(Foo, b)
        }

        assert_eq!([0; test_fn()].len(), 4);
    }
}
<|endoftext|>


<commit_before>use std::mem::transmute;
use std::os::unix::io::AsRawFd;
use std::time::Duration;
use std::thread::sleep;
use std::io::Write;

use wayland_client::wayland::get_display;
use wayland_client::wayland::compositor::{WlCompositor, WlSurface};
use wayland_client::wayland::shell::{WlShellSurface, WlShell};
use wayland_client::wayland::shm::{WlBuffer, WlShm, WlShmFormat};
use wayland_client::wayland::seat::{WlSeat, WlPointerEvent};
use wayland_client::wayland::WlDisplay;
use wayland_client::cursor::{CursorTheme, Cursor, load_theme};
use wayland_client::{EventIterator, Proxy};

use rustwlc::WlcOutput;
use tempfile;

use byteorder::{NativeEndian, WriteBytesExt};

wayland_env!(WaylandEnv,
             compositor: WlCompositor,
             shell: WlShell,
             shm: WlShm,
             seat: WlSeat
);

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
/// Holds the bytes to represent a colored background.
/// To be written into a wayland surface.
pub struct Color(pub [u8; 4]);

impl Color {
    /// Generate a new color out of a u32.
    /// E.G: 0xFFFFFFFF
    pub fn from_u32(color: u32) -> Self {
        unsafe { Color(transmute(color)) }
    }
}

pub fn generate_solid_background(color: Color, output: WlcOutput) {
    // Get shortcuts to the globals.
    let (display, iter) = get_display()
        .expect("Unable to connect to a wayland compositor");
    let (env, mut evt_iter) = WaylandEnv::init(display, iter);
    let compositor = env.compositor.as_ref().map(|o| &o.0).unwrap();
    let shell = env.shell.as_ref().map(|o| &o.0).unwrap();
    let shm = env.shm.as_ref().map(|o| &o.0).unwrap();
    let seat = env.seat.as_ref().map(|o| &o.0).unwrap();

    // Create the surface we are going to write into
    let surface = compositor.create_surface();
    let shell_surface = shell.get_shell_surface(&surface);
    let mut tmp = tempfile::tempfile().ok().expect("Unable to create a tempfile.");

    // Calculate how big the buffer needs to be from the output resolution
    let resolution = output.get_resolution().clone();
    let (width, height) = (resolution.w as i32, resolution.h as i32);
    let size = (resolution.w * resolution.h) as i32;

    // Write in the color coding to the surface
    for _ in 0..size {
        unsafe {
            tmp.write_u32::<NativeEndian>(transmute(color.0))
                .expect("Could not write to file")
        }
    }
    tmp.flush()
        .expect("Could not flush buffer");

    // Create the buffer that is mem-mapped to the temp file descriptor
    let pool = shm.create_pool(tmp.as_raw_fd(), size);
    let buffer = pool.create_buffer(0, width, height, width, WlShmFormat::Argb8888);
    // Tell Way Cooler not to set put this in the tree, treat as background
    shell_surface.set_class("Background".into());

    // Attach the buffer to the surface
    surface.attach(Some(&buffer), 0, 0);
    surface.set_buffer_scale(4);
    surface.commit();
    evt_iter.sync_roundtrip().unwrap();

    main_background_loop(compositor, shell, shm, seat, surface,
                         shell_surface, buffer, evt_iter);
}

/// Main loop for rendering backgrounds.
/// Need to keep the surface alive, and update it if the
/// user wants to change the background.
#[allow(unused_variables)]
fn main_background_loop(compositor: &WlCompositor, shell: &WlShell, shm: &WlShm,
                        seat: &WlSeat,
                        surface: WlSurface, shell_surface: WlShellSurface,
                        buffer: WlBuffer, mut event_iter: EventIterator) {
    use wayland_client::wayland::WaylandProtocolEvent;
    use wayland_client::Event;
    println!("Entering main loop");
    // For now just loop and do nothing
    // Eventually need to query the background state and update
    let cursor_surface = compositor.create_surface();
    let mut pointer = seat.get_pointer();
    let cursor_theme = load_theme(None, 16, shm);
    // TODO Figure out why not working on Timidger's machine
    let cursor = cursor_theme.get_cursor("default")
        .expect("Couldn't load cursor from theme");
    let cursor_buffer = cursor.frame_buffer(0).expect("Couldn't get frame_buffer");
    cursor_surface.attach(Some(&*cursor_buffer), 0, 0);
    pointer.set_event_iterator(&event_iter);

    pointer.set_cursor(0/*??*/, Some(&cursor_surface), 0, 0);
    loop {
        for event in &mut event_iter {
            match event {
                Event::Wayland(wayland_event) => {
                    match wayland_event {
                        WaylandProtocolEvent::WlPointer(id, pointer_event) => {
                            match pointer_event {
                                WlPointerEvent::Enter(serial, surface, surface_x, surface_y) => {
                                    // Set the surface to use a cursor
                                    pointer.set_cursor(0/*??*/, Some(&cursor_surface), 0, 0);
                                },
                                _ => {
                                }
                            }
                        },
                        _ => {/* unhandled events */}
                    }
                }
                _ => { /* unhandled events */ }
            }
        }
        event_iter.dispatch().expect("Connection with the compositor was lost.");
    }
}
<commit_msg>When cursor can't load, background doesn't flash<commit_after>use std::mem::transmute;
use std::os::unix::io::AsRawFd;
use std::time::Duration;
use std::thread::sleep;
use std::io::Write;

use wayland_client::wayland::get_display;
use wayland_client::wayland::compositor::{WlCompositor, WlSurface};
use wayland_client::wayland::shell::{WlShellSurface, WlShell};
use wayland_client::wayland::shm::{WlBuffer, WlShm, WlShmFormat};
use wayland_client::wayland::seat::{WlSeat, WlPointerEvent};
use wayland_client::wayland::WlDisplay;
use wayland_client::cursor::{CursorTheme, Cursor, load_theme};
use wayland_client::{EventIterator, Proxy};

use rustwlc::WlcOutput;
use tempfile;

use byteorder::{NativeEndian, WriteBytesExt};

wayland_env!(WaylandEnv,
             compositor: WlCompositor,
             shell: WlShell,
             shm: WlShm,
             seat: WlSeat
);

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
/// Holds the bytes to represent a colored background.
/// To be written into a wayland surface.
pub struct Color(pub [u8; 4]);

impl Color {
    /// Generate a new color out of a u32.
    /// E.G: 0xFFFFFFFF
    pub fn from_u32(color: u32) -> Self {
        unsafe { Color(transmute(color)) }
    }
}

pub fn generate_solid_background(color: Color, output: WlcOutput) {
    // Get shortcuts to the globals.
    let (display, iter) = get_display()
        .expect("Unable to connect to a wayland compositor");
    let (env, mut evt_iter) = WaylandEnv::init(display, iter);
    let compositor = env.compositor.as_ref().map(|o| &o.0).unwrap();
    let shell = env.shell.as_ref().map(|o| &o.0).unwrap();
    let shm = env.shm.as_ref().map(|o| &o.0).unwrap();
    let seat = env.seat.as_ref().map(|o| &o.0).unwrap();

    // Create the surface we are going to write into
    let surface = compositor.create_surface();
    let shell_surface = shell.get_shell_surface(&surface);
    let mut tmp = tempfile::tempfile().ok().expect("Unable to create a tempfile.");

    // Calculate how big the buffer needs to be from the output resolution
    let resolution = output.get_resolution().clone();
    let (width, height) = (resolution.w as i32, resolution.h as i32);
    let size = (resolution.w * resolution.h) as i32;

    // Write in the color coding to the surface
    for _ in 0..size {
        unsafe {
            tmp.write_u32::<NativeEndian>(transmute(color.0))
                .expect("Could not write to file")
        }
    }
    tmp.flush()
        .expect("Could not flush buffer");

    // Create the buffer that is mem-mapped to the temp file descriptor
    let pool = shm.create_pool(tmp.as_raw_fd(), size);
    let buffer = pool.create_buffer(0, width, height, width, WlShmFormat::Argb8888);
    // Tell Way Cooler not to set put this in the tree, treat as background
    shell_surface.set_class("Background".into());

    // Attach the buffer to the surface
    surface.attach(Some(&buffer), 0, 0);
    surface.set_buffer_scale(4);

    main_background_loop(compositor, shell, shm, seat, surface,
                         shell_surface, buffer, evt_iter);
}

/// Main loop for rendering backgrounds.
/// Need to keep the surface alive, and update it if the
/// user wants to change the background.
#[allow(unused_variables)]
fn main_background_loop(compositor: &WlCompositor, shell: &WlShell, shm: &WlShm,
                        seat: &WlSeat,
                        surface: WlSurface, shell_surface: WlShellSurface,
                        buffer: WlBuffer, mut event_iter: EventIterator) {
    use wayland_client::wayland::WaylandProtocolEvent;
    use wayland_client::Event;
    println!("Entering main loop");
    // For now just loop and do nothing
    // Eventually need to query the background state and update
    let cursor_surface = compositor.create_surface();
    let mut pointer = seat.get_pointer();
    let cursor_theme = load_theme(None, 16, shm);
    // TODO Figure out why not working on Timidger's machine
    let cursor = cursor_theme.get_cursor("default")
        .expect("Couldn't load cursor from theme");
    let cursor_buffer = cursor.frame_buffer(0).expect("Couldn't get frame_buffer");
    cursor_surface.attach(Some(&*cursor_buffer), 0, 0);
    pointer.set_event_iterator(&event_iter);
    pointer.set_cursor(0, Some(&cursor_surface), 0, 0);
    surface.commit();
    event_iter.sync_roundtrip().unwrap();
    loop {
        for event in &mut event_iter {
            match event {
                Event::Wayland(wayland_event) => {
                    match wayland_event {
                        WaylandProtocolEvent::WlPointer(id, pointer_event) => {
                            match pointer_event {
                                WlPointerEvent::Enter(serial, surface, surface_x, surface_y) => {
                                    // Set the surface to use a cursor
                                    pointer.set_cursor(0, Some(&cursor_surface), 0, 0);
                                },
                                _ => {
                                }
                            }
                        },
                        _ => {/* unhandled events */}
                    }
                }
                _ => { /* unhandled events */ }
            }
        }
        event_iter.dispatch().expect("Connection with the compositor was lost.");
    }
}
<|endoftext|>


<commit_before>//! Trait solving using Chalk.

use std::env::var;

use chalk_ir::GoalData;
use chalk_recursive::Cache;
use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};

use base_db::CrateId;
use hir_def::{lang_item::LangItemTarget, TraitId};
use stdx::panic_context;
use syntax::SmolStr;

use crate::{
    db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
    Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
};

/// This controls how much 'time' we give the Chalk solver before giving up.
const CHALK_SOLVER_FUEL: i32 = 100;

#[derive(Debug, Copy, Clone)]
pub(crate) struct ChalkContext<'a> {
    pub(crate) db: &'a dyn HirDatabase,
    pub(crate) krate: CrateId,
}

fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
    let overflow_depth =
        var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(300);
    let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(150);
    chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, Some(Cache::new()))
}

/// A set of clauses that we assume to be true. E.g. if we are inside this function:
/// ```rust
/// fn foo<T: Default>(t: T) {}
/// ```
/// we assume that `T: Default`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TraitEnvironment {
    pub krate: CrateId,
    // FIXME make this a BTreeMap
    pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
    pub env: chalk_ir::Environment<Interner>,
}

impl TraitEnvironment {
    pub fn empty(krate: CrateId) -> Self {
        TraitEnvironment {
            krate,
            traits_from_clauses: Vec::new(),
            env: chalk_ir::Environment::new(Interner),
        }
    }

    pub fn traits_in_scope_from_clauses<'a>(
        &'a self,
        ty: Ty,
    ) -> impl Iterator<Item = TraitId> + 'a {
        self.traits_from_clauses
            .iter()
            .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then(|| *trait_id))
    }
}

/// Solve a trait goal using Chalk.
pub(crate) fn trait_solve_query(
    db: &dyn HirDatabase,
    krate: CrateId,
    goal: Canonical<InEnvironment<Goal>>,
) -> Option<Solution> {
    let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) {
        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
            db.trait_data(it.hir_trait_id()).name.to_string()
        }
        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(),
        _ => "??".to_string(),
    });
    tracing::info!("trait_solve_query({:?})", goal.value.goal);

    if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
        alias: AliasTy::Projection(projection_ty),
        ..
    }))) = &goal.value.goal.data(Interner)
    {
        if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(Interner).kind(Interner) {
            // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
            return Some(Solution::Ambig(Guidance::Unknown));
        }
    }

    // We currently don't deal with universes (I think / hope they're not yet
    // relevant for our use cases?)
    let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
    solve(db, krate, &u_canonical)
}

fn solve(
    db: &dyn HirDatabase,
    krate: CrateId,
    goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
) -> Option<chalk_solve::Solution<Interner>> {
    let context = ChalkContext { db, krate };
    tracing::debug!("solve goal: {:?}", goal);
    let mut solver = create_chalk_solver();

    let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);

    let should_continue = || {
        db.unwind_if_cancelled();
        let remaining = fuel.get();
        fuel.set(remaining - 1);
        if remaining == 0 {
            tracing::debug!("fuel exhausted");
        }
        remaining > 0
    };

    let mut solve = || {
        let _ctx = if is_chalk_debug() || is_chalk_print() {
            Some(panic_context::enter(format!("solving {:?}", goal)))
        } else {
            None
        };
        let solution = if is_chalk_print() {
            let logging_db =
                LoggingRustIrDatabaseLoggingOnDrop(LoggingRustIrDatabase::new(context));
            solver.solve_limited(&logging_db.0, goal, &should_continue)
        } else {
            solver.solve_limited(&context, goal, &should_continue)
        };

        tracing::debug!("solve({:?}) => {:?}", goal, solution);

        solution
    };

    // don't set the TLS for Chalk unless Chalk debugging is active, to make
    // extra sure we only use it for debugging
    if is_chalk_debug() {
        crate::tls::set_current_program(db, solve)
    } else {
        solve()
    }
}

struct LoggingRustIrDatabaseLoggingOnDrop<'a>(LoggingRustIrDatabase<Interner, ChalkContext<'a>>);

impl<'a> Drop for LoggingRustIrDatabaseLoggingOnDrop<'a> {
    fn drop(&mut self) {
        eprintln!("chalk program:\n{}", self.0);
    }
}

fn is_chalk_debug() -> bool {
    std::env::var("CHALK_DEBUG").is_ok()
}

fn is_chalk_print() -> bool {
    std::env::var("CHALK_PRINT").is_ok()
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FnTrait {
    FnOnce,
    FnMut,
    Fn,
}

impl FnTrait {
    const fn lang_item_name(self) -> &'static str {
        match self {
            FnTrait::FnOnce => "fn_once",
            FnTrait::FnMut => "fn_mut",
            FnTrait::Fn => "fn",
        }
    }

    pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
        let target = db.lang_item(krate, SmolStr::new_inline(self.lang_item_name()))?;
        match target {
            LangItemTarget::TraitId(t) => Some(t),
            _ => None,
        }
    }
}
<commit_msg>Increase defalt chalk overflow depth to match max solver size<commit_after>//! Trait solving using Chalk.

use std::env::var;

use chalk_ir::GoalData;
use chalk_recursive::Cache;
use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};

use base_db::CrateId;
use hir_def::{lang_item::LangItemTarget, TraitId};
use stdx::panic_context;
use syntax::SmolStr;

use crate::{
    db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
    Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
};

/// This controls how much 'time' we give the Chalk solver before giving up.
const CHALK_SOLVER_FUEL: i32 = 100;

#[derive(Debug, Copy, Clone)]
pub(crate) struct ChalkContext<'a> {
    pub(crate) db: &'a dyn HirDatabase,
    pub(crate) krate: CrateId,
}

fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
    let overflow_depth =
        var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(500);
    let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(150);
    chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, Some(Cache::new()))
}

/// A set of clauses that we assume to be true. E.g. if we are inside this function:
/// ```rust
/// fn foo<T: Default>(t: T) {}
/// ```
/// we assume that `T: Default`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TraitEnvironment {
    pub krate: CrateId,
    // FIXME make this a BTreeMap
    pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
    pub env: chalk_ir::Environment<Interner>,
}

impl TraitEnvironment {
    pub fn empty(krate: CrateId) -> Self {
        TraitEnvironment {
            krate,
            traits_from_clauses: Vec::new(),
            env: chalk_ir::Environment::new(Interner),
        }
    }

    pub fn traits_in_scope_from_clauses<'a>(
        &'a self,
        ty: Ty,
    ) -> impl Iterator<Item = TraitId> + 'a {
        self.traits_from_clauses
            .iter()
            .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then(|| *trait_id))
    }
}

/// Solve a trait goal using Chalk.
pub(crate) fn trait_solve_query(
    db: &dyn HirDatabase,
    krate: CrateId,
    goal: Canonical<InEnvironment<Goal>>,
) -> Option<Solution> {
    let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) {
        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
            db.trait_data(it.hir_trait_id()).name.to_string()
        }
        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(),
        _ => "??".to_string(),
    });
    tracing::info!("trait_solve_query({:?})", goal.value.goal);

    if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
        alias: AliasTy::Projection(projection_ty),
        ..
    }))) = &goal.value.goal.data(Interner)
    {
        if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(Interner).kind(Interner) {
            // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
            return Some(Solution::Ambig(Guidance::Unknown));
        }
    }

    // We currently don't deal with universes (I think / hope they're not yet
    // relevant for our use cases?)
    let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
    solve(db, krate, &u_canonical)
}

fn solve(
    db: &dyn HirDatabase,
    krate: CrateId,
    goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
) -> Option<chalk_solve::Solution<Interner>> {
    let context = ChalkContext { db, krate };
    tracing::debug!("solve goal: {:?}", goal);
    let mut solver = create_chalk_solver();

    let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);

    let should_continue = || {
        db.unwind_if_cancelled();
        let remaining = fuel.get();
        fuel.set(remaining - 1);
        if remaining == 0 {
            tracing::debug!("fuel exhausted");
        }
        remaining > 0
    };

    let mut solve = || {
        let _ctx = if is_chalk_debug() || is_chalk_print() {
            Some(panic_context::enter(format!("solving {:?}", goal)))
        } else {
            None
        };
        let solution = if is_chalk_print() {
            let logging_db =
                LoggingRustIrDatabaseLoggingOnDrop(LoggingRustIrDatabase::new(context));
            solver.solve_limited(&logging_db.0, goal, &should_continue)
        } else {
            solver.solve_limited(&context, goal, &should_continue)
        };

        tracing::debug!("solve({:?}) => {:?}", goal, solution);

        solution
    };

    // don't set the TLS for Chalk unless Chalk debugging is active, to make
    // extra sure we only use it for debugging
    if is_chalk_debug() {
        crate::tls::set_current_program(db, solve)
    } else {
        solve()
    }
}

struct LoggingRustIrDatabaseLoggingOnDrop<'a>(LoggingRustIrDatabase<Interner, ChalkContext<'a>>);

impl<'a> Drop for LoggingRustIrDatabaseLoggingOnDrop<'a> {
    fn drop(&mut self) {
        eprintln!("chalk program:\n{}", self.0);
    }
}

fn is_chalk_debug() -> bool {
    std::env::var("CHALK_DEBUG").is_ok()
}

fn is_chalk_print() -> bool {
    std::env::var("CHALK_PRINT").is_ok()
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FnTrait {
    FnOnce,
    FnMut,
    Fn,
}

impl FnTrait {
    const fn lang_item_name(self) -> &'static str {
        match self {
            FnTrait::FnOnce => "fn_once",
            FnTrait::FnMut => "fn_mut",
            FnTrait::Fn => "fn",
        }
    }

    pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
        let target = db.lang_item(krate, SmolStr::new_inline(self.lang_item_name()))?;
        match target {
            LangItemTarget::TraitId(t) => Some(t),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display, Formatter};

#[derive(Debug, PartialEq)]
pub enum MarkupDisplay<T> where T: Display {
    Safe(T),
    Unsafe(T),
}

impl<T> MarkupDisplay<T> where T: Display {
    pub fn mark_safe(self) -> MarkupDisplay<T> {
        match self {
            MarkupDisplay::Unsafe(t) => MarkupDisplay::Safe(t),
            _ => { self },
        }
    }
    pub fn unsafe_string(&self) -> String {
        match *self {
            MarkupDisplay::Safe(ref t) | MarkupDisplay::Unsafe(ref t) => format!("{}", t)
        }
    }
}

impl<T> From<T> for MarkupDisplay<T> where T: Display {
    fn from(t: T) -> MarkupDisplay<T> {
        MarkupDisplay::Unsafe(t)
    }
}

impl<T> Display for MarkupDisplay<T> where T: Display {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            MarkupDisplay::Unsafe(_) => {
                write!(f, "{}", escape(self.unsafe_string()))
            },
            MarkupDisplay::Safe(ref t) => {
                t.fmt(f)
            },
        }
    }
}

fn escapable(b: &u8) -> bool {
    *b == b'<' || *b == b'>' || *b == b'&' || *b == b'"' || *b == b'\'' || *b == b'/'
}

pub fn escape(s: String) -> String {
    let mut found = Vec::new();
    for (i, b) in s.as_bytes().iter().enumerate() {
        if escapable(b) {
            found.push(i);
        }
    }
    if found.is_empty() {
        return s;
    }

    let bytes = s.as_bytes();
    let max_len = bytes.len() + found.len() * 5;
    let mut res = Vec::<u8>::with_capacity(max_len);
    let mut start = 0;
    for idx in &found {
        if start < *idx {
            res.extend(&bytes[start..*idx]);
        }
        start = *idx + 1;
        match bytes[*idx] {
            b'<' => { res.extend(b"<"); },
            b'>' => { res.extend(b">"); },
            b'&' => { res.extend(b"&"); },
            b'"' => { res.extend(b"""); },
            b'\'' => { res.extend(b"'"); },
            b'/' => { res.extend(b"/"); },
            _ => panic!("incorrect indexing"),
        }
    }
    if start < bytes.len() - 1 {
        res.extend(&bytes[start..]);
    }

    String::from_utf8(res).unwrap()
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_escape() {
        assert_eq!(escape("".to_string()), "");
        assert_eq!(escape("<&>".to_string()), "<&>");
        assert_eq!(escape("bla&".to_string()), "bla&");
        assert_eq!(escape("<foo".to_string()), "<foo");
    }
}
<commit_msg>Rewrite escapable() to prevent duplication<commit_after>use std::fmt::{self, Display, Formatter};

#[derive(Debug, PartialEq)]
pub enum MarkupDisplay<T> where T: Display {
    Safe(T),
    Unsafe(T),
}

impl<T> MarkupDisplay<T> where T: Display {
    pub fn mark_safe(self) -> MarkupDisplay<T> {
        match self {
            MarkupDisplay::Unsafe(t) => MarkupDisplay::Safe(t),
            _ => { self },
        }
    }
    pub fn unsafe_string(&self) -> String {
        match *self {
            MarkupDisplay::Safe(ref t) | MarkupDisplay::Unsafe(ref t) => format!("{}", t)
        }
    }
}

impl<T> From<T> for MarkupDisplay<T> where T: Display {
    fn from(t: T) -> MarkupDisplay<T> {
        MarkupDisplay::Unsafe(t)
    }
}

impl<T> Display for MarkupDisplay<T> where T: Display {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            MarkupDisplay::Unsafe(_) => {
                write!(f, "{}", escape(self.unsafe_string()))
            },
            MarkupDisplay::Safe(ref t) => {
                t.fmt(f)
            },
        }
    }
}

fn escapable(b: u8) -> bool {
    match b {
        b'<' | b'>' | b'&' | b'"' | b'\'' | b'/' => true,
        _ => false,
    }
}

pub fn escape(s: String) -> String {
    let mut found = Vec::new();
    for (i, b) in s.as_bytes().iter().enumerate() {
        if escapable(*b) {
            found.push(i);
        }
    }
    if found.is_empty() {
        return s;
    }

    let bytes = s.as_bytes();
    let max_len = bytes.len() + found.len() * 5;
    let mut res = Vec::<u8>::with_capacity(max_len);
    let mut start = 0;
    for idx in &found {
        if start < *idx {
            res.extend(&bytes[start..*idx]);
        }
        start = *idx + 1;
        match bytes[*idx] {
            b'<' => { res.extend(b"<"); },
            b'>' => { res.extend(b">"); },
            b'&' => { res.extend(b"&"); },
            b'"' => { res.extend(b"""); },
            b'\'' => { res.extend(b"'"); },
            b'/' => { res.extend(b"/"); },
            _ => panic!("incorrect indexing"),
        }
    }
    if start < bytes.len() - 1 {
        res.extend(&bytes[start..]);
    }

    String::from_utf8(res).unwrap()
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_escape() {
        assert_eq!(escape("".to_string()), "");
        assert_eq!(escape("<&>".to_string()), "<&>");
        assert_eq!(escape("bla&".to_string()), "bla&");
        assert_eq!(escape("<foo".to_string()), "<foo");
    }
}
<|endoftext|>