<commit_before>// (c) 2016 Joost Yervante Damad <joost@productize.be>

use std::fmt;
use std::path::PathBuf;

// from parent
use ERes;
use err;
use read_file;
use footprint;

extern crate rustysexp;
use self::rustysexp::Sexp;

pub struct Layout {
    pub version:i64,
    pub setup:Setup,
    pub elements:Vec<Element>,
}

#[derive(Clone)]
pub enum Element {
    Module(footprint::Module),
    Net(Net),
    NetClass(NetClass),
    Other(Sexp),
}

#[derive(Clone)]
pub struct Setup {
    pub elements:Vec<(String, String)>,
    pub pcbplotparams:Option<Sexp>,
}

#[derive(Clone,PartialEq)]
pub struct Net {
    pub num:i64,
    pub name:String,
}

#[derive(Clone,PartialEq)]
pub struct NetClass {
    pub name:String,
    pub desc:String,
    pub clearance:f64,
    pub trace_width:f64,
    pub via_dia:f64,
    pub via_drill:f64,
    pub uvia_dia:f64,
    pub uvia_drill:f64,
    pub nets:Vec<String>,
}

impl Layout {
    pub fn new() -> Layout {
        Layout {
            version:0,
            elements:vec![],
            setup:Setup::new(),
        }
    }

    pub fn nets(&self) -> Vec<&Net> {
        let mut v = vec![];
        for element in &self.elements {
            match *element {
                Element::Net(ref net) => v.push(net),
                _ => (),
            }
        }
        v
    }

    pub fn netclasses(&self) -> Vec<&NetClass> {
        let mut v = vec![];
        for element in &self.elements {
            match *element {
                Element::NetClass(ref net_class) => v.push(net_class),
                _ => (),
            }
        }
        v
    }

    pub fn modify_module<F>(&mut self, reference:&String, fun:F) -> ERes<()>
        where F:Fn(&mut footprint::Module) -> ()
    {
        for ref mut x in &mut self.elements[..] {
            match **x {
                Element::Module(ref mut m) => {
                    if m.is_reference(reference) {
                        return Ok(fun(m))
                    }
                },
                Element::Net(_) => (),
                Element::NetClass(_) => (),
                Element::Other(_) => (),
            }
        }
        Err(format!("did not find module with reference {}", reference))
    }

    pub fn add_net(&mut self, num:i64, name:&'static str) {
        self.elements.push(Element::Net(Net { num:num, name:String::from(name) }));
    }
    pub fn add_netclass(&mut self, name:&'static str, desc:&'static str, clearance:f64, trace_width:f64, via_dia:f64, via_drill:f64, uvia_dia:f64, uvia_drill:f64, nets:Vec<String>) {
        self.elements.push(Element::NetClass(NetClass {
            name:String::from(name),
            desc:String::from(desc),
            clearance:clearance,
            trace_width:trace_width,
            via_dia:via_dia,
            via_drill:via_drill,
            uvia_dia:uvia_dia,
            uvia_drill:uvia_drill,
            nets:nets
            }));
    }
}

impl NetClass {
    pub fn equal_no_net(&self, other:&NetClass) -> bool {
        let mut s1 = self.clone();
        s1.nets = vec![];
        let mut s2 = other.clone();
        s2.nets = vec![];
        return s1 == s2;
    }
    pub fn has_net(&self, name:&'static str) -> bool {
        for net in &self.nets {
            if &net[..] == name {
                return true
            }
        }
        return false
    }
}

impl Setup {
    pub fn new() -> Setup {
        Setup { elements:vec![],pcbplotparams:Some(Sexp::List(vec![Sexp::String(String::from("pcbplotparams"))]))}
    }
    pub fn get(&self, s:&String) -> Option<&String> {
        for element in &self.elements {
            if element.0[..] == s[..] {
                return Some(&element.1)
            }
        }
        return None
    }

    pub fn update_element(&mut self, name:&String, value:String) {
        for element in &mut self.elements {
            if element.0[..] == name[..] {
                element.1 = value;
                return;

            }
        }
        self.elements.push((name.clone(), value));
    }
}

impl fmt::Display for Layout {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "(kicad_pcb (version {})", self.version));
        let mut i = 0;
        for element in &self.elements[..] {
            try!(writeln!(f, "  {}", element));
            try!(writeln!(f, ""));
            // kludge to put setup at the right order in the file
            if i == 3 {
                try!(writeln!(f, "  {}", self.setup));
            }
            i+=1;
        }
        writeln!(f, ")")
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Element::Other(ref s) => write!(f, "{}", s),
            Element::Module(ref s) => write!(f, "{}", s),
            Element::Net(ref s) => write!(f, "{}", s),
            Element::NetClass(ref s) => write!(f, "{}", s),
        }
    }
}

impl fmt::Display for Net {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        if self.name.contains("(") || self.name.contains(")") || self.name.len()==0 {
            write!(f, "(net {} \"{}\")", self.num, self.name)
        } else {
            write!(f, "(net {} {})", self.num, self.name)
        }
    }
}
impl fmt::Display for NetClass {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(net_class {} {} ", self.name, rustysexp::display_string(&self.desc)));
        try!(write!(f, "(clearance {}) ", self.clearance));
        try!(write!(f, "(trace_width {}) ", self.trace_width));
        try!(write!(f, "(via_dia {}) ", self.via_dia));
        try!(write!(f, "(via_drill {}) ", self.via_drill));
        try!(write!(f, "(uvia_dia {}) ", self.uvia_dia));
        try!(write!(f, "(uvia_drill {}) ", self.uvia_drill));
        for net in &self.nets {
            if net.contains("(") || net.contains(")") {
                try!(write!(f, "(add_net \"{}\")", net))
            } else {
                try!(write!(f, "(add_net {})", net))
            }
        }
        write!(f, ")")

    }
}

impl fmt::Display for Setup {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "(setup"));
        for ref k in &self.elements {
            try!(writeln!(f, "   ({} {})", k.0, k.1));
        }
        match self.pcbplotparams {
            None => writeln!(f, ")"),
            Some(ref s) => writeln!(f, " {})", s),
        }
    }
}

fn parse_version(e:&Sexp) -> ERes<i64> {
    let l = try!(e.slice_atom("version"));
    l[0].i()
}

fn parse_other(e:&Sexp) -> Element {
    let e2 = e.clone();
    Element::Other(e2)
}

fn parse_module(e:&Sexp) -> ERes<Element> {
    let e2 = e.clone();
    let m = try!(footprint::parse_module(e2));
    Ok(Element::Module(m))
}

fn parse_net(e:&Sexp) -> ERes<Element> {
    let l = try!(e.slice_atom("net"));
    let num = try!(l[0].i());
    let name = try!(l[1].string()).clone();
    Ok(Element::Net(Net { name:name, num:num }))
}

fn parse_net_class(e:&Sexp) -> ERes<Element> {
    fn parse(e:&Sexp, name:&str) -> ERes<f64> {
        let l = try!(e.slice_atom(name));
        l[0].f()
    }
    let l = try!(e.slice_atom("net_class"));
    let name = try!(l[0].string()).clone();
    let desc = try!(l[1].string()).clone();
    let mut clearance = 0.1524;
    let mut trace_width = 0.2032;
    let mut via_dia = 0.675;
    let mut via_drill = 0.25;
    let mut uvia_dia = 0.508;
    let mut uvia_drill = 0.127;
    let mut nets = vec![];
    for x in &l[2..] {
        let list_name = try!(x.list_name());
        let xn = &list_name[..];
        match xn {
            "add_net" => {
                let l1 = try!(x.slice_atom("add_net"));
                nets.push(try!(l1[0].string()).clone())
            },
            "clearance" => clearance = try!(parse(x, xn)),
            "trace_width" => trace_width = try!(parse(x, xn)),
            "via_dia" => via_dia = try!(parse(x, xn)),
            "via_drill" => via_drill = try!(parse(x, xn)),
            "uvia_dia" => uvia_dia = try!(parse(x, xn)),
            "uvia_drill" => uvia_drill = try!(parse(x, xn)),
            _ => return Err(format!("unknown net_class field {}", list_name))
        }
    }
    let net_class = NetClass {
        name:name, desc:desc, clearance:clearance, via_dia:via_dia,
        via_drill:via_drill, uvia_dia:uvia_dia, uvia_drill:uvia_drill,
        nets:nets, trace_width:trace_width,
    };
    Ok(Element::NetClass(net_class))
}

fn parse_setup(e:&Sexp) -> ERes<Setup> {
    let mut h = vec![];
    let mut pcbplotparams = None;
    for v in try!(e.slice_atom("setup")) {
        let n = v.list_name().unwrap().clone();
        match &n[..] {
            "pcbplotparams" => { pcbplotparams = Some(v.clone()); },
            x => {
                // TODO: this is a kludge, implement proper data type for Setup
                let v2 = v.slice_atom(x).unwrap();
                let mut s = String::new();
                let mut first = true;
                for z in v2 {
                    if !first { s.push_str(" ") };
                    first = false;
                    s.push_str(z.string().unwrap());
                }
                h.push((n.clone(), s));
            },
        }
    }
    let s = Setup { elements:h , pcbplotparams:pcbplotparams };
    Ok(s)
}

fn parse(s: &str) -> ERes<Layout> {
    let exp = match rustysexp::parse_str(s) {
        Ok(s) => s,
        Err(x) => return Err(format!("ParseError: {}", x)),
    };
    let l1 = try!(exp.slice_atom("kicad_pcb"));
    let mut layout = Layout::new();

    for ref e in l1 {
        match &try!(e.list_name())[..] {
            "version" => layout.version = try!(parse_version(e)),
            "module" => layout.elements.push(try!(parse_module(e))),
            "net" => layout.elements.push(try!(parse_net(e))),
            "net_class" => layout.elements.push(try!(parse_net_class(e))),
            "setup" => layout.setup = try!(parse_setup(e)),
            _ => layout.elements.push(parse_other(e)),
        }
    }
    Ok(layout)
}

pub fn parse_str(s: &str) -> ERes<Layout> {
    parse(s)
}

pub fn parse_file(filename: &PathBuf) -> ERes<Layout> {
    let name = filename.to_str().unwrap();
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => Err(format!("io error: {}", x))
    });
    parse(&s[..])
}
<commit_msg>static<commit_after>// (c) 2016 Joost Yervante Damad <joost@productize.be>

use std::fmt;
use std::path::PathBuf;

// from parent
use ERes;
use err;
use read_file;
use footprint;

extern crate rustysexp;
use self::rustysexp::Sexp;

pub struct Layout {
    pub version:i64,
    pub setup:Setup,
    pub elements:Vec<Element>,
}

#[derive(Clone)]
pub enum Element {
    Module(footprint::Module),
    Net(Net),
    NetClass(NetClass),
    Other(Sexp),
}

#[derive(Clone)]
pub struct Setup {
    pub elements:Vec<(String, String)>,
    pub pcbplotparams:Option<Sexp>,
}

#[derive(Clone,PartialEq)]
pub struct Net {
    pub num:i64,
    pub name:String,
}

#[derive(Clone,PartialEq)]
pub struct NetClass {
    pub name:String,
    pub desc:String,
    pub clearance:f64,
    pub trace_width:f64,
    pub via_dia:f64,
    pub via_drill:f64,
    pub uvia_dia:f64,
    pub uvia_drill:f64,
    pub nets:Vec<String>,
}

impl Layout {
    pub fn new() -> Layout {
        Layout {
            version:0,
            elements:vec![],
            setup:Setup::new(),
        }
    }

    pub fn nets(&self) -> Vec<&Net> {
        let mut v = vec![];
        for element in &self.elements {
            match *element {
                Element::Net(ref net) => v.push(net),
                _ => (),
            }
        }
        v
    }

    pub fn netclasses(&self) -> Vec<&NetClass> {
        let mut v = vec![];
        for element in &self.elements {
            match *element {
                Element::NetClass(ref net_class) => v.push(net_class),
                _ => (),
            }
        }
        v
    }

    pub fn modify_module<F>(&mut self, reference:&String, fun:F) -> ERes<()>
        where F:Fn(&mut footprint::Module) -> ()
    {
        for ref mut x in &mut self.elements[..] {
            match **x {
                Element::Module(ref mut m) => {
                    if m.is_reference(reference) {
                        return Ok(fun(m))
                    }
                },
                Element::Net(_) => (),
                Element::NetClass(_) => (),
                Element::Other(_) => (),
            }
        }
        Err(format!("did not find module with reference {}", reference))
    }

    pub fn add_net(&mut self, num:i64, name:&'static str) {
        self.elements.push(Element::Net(Net { num:num, name:String::from(name) }));
    }
    pub fn add_netclass(&mut self, name:&'static str, desc:&'static str, clearance:f64, trace_width:f64, via_dia:f64, via_drill:f64, uvia_dia:f64, uvia_drill:f64, nets:Vec<String>) {
        self.elements.push(Element::NetClass(NetClass {
            name:String::from(name),
            desc:String::from(desc),
            clearance:clearance,
            trace_width:trace_width,
            via_dia:via_dia,
            via_drill:via_drill,
            uvia_dia:uvia_dia,
            uvia_drill:uvia_drill,
            nets:nets
            }));
    }
}

impl NetClass {
    pub fn equal_no_net(&self, other:&NetClass) -> bool {
        let mut s1 = self.clone();
        s1.nets = vec![];
        let mut s2 = other.clone();
        s2.nets = vec![];
        return s1 == s2;
    }
    pub fn has_net(&self, name:&'static str) -> bool {
        for net in &self.nets {
            if &net[..] == name {
                return true
            }
        }
        return false
    }
}

impl Setup {
    pub fn new() -> Setup {
        Setup { elements:vec![],pcbplotparams:Some(Sexp::List(vec![Sexp::String(String::from("pcbplotparams"))]))}
    }
    pub fn get(&self, s:&String) -> Option<&String> {
        for element in &self.elements {
            if &element.0[..] == &s[..] {
                return Some(&element.1)
            }
        }
        return None
    }

    pub fn update_element(&mut self, name:&'static str, value:String) {
        for element in &mut self.elements {
            if &element.0[..] == name {
                element.1 = value;
                return;

            }
        }
        self.elements.push((String::from(name), value));
    }
}

impl fmt::Display for Layout {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "(kicad_pcb (version {})", self.version));
        let mut i = 0;
        for element in &self.elements[..] {
            try!(writeln!(f, "  {}", element));
            try!(writeln!(f, ""));
            // kludge to put setup at the right order in the file
            if i == 3 {
                try!(writeln!(f, "  {}", self.setup));
            }
            i+=1;
        }
        writeln!(f, ")")
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Element::Other(ref s) => write!(f, "{}", s),
            Element::Module(ref s) => write!(f, "{}", s),
            Element::Net(ref s) => write!(f, "{}", s),
            Element::NetClass(ref s) => write!(f, "{}", s),
        }
    }
}

impl fmt::Display for Net {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        if self.name.contains("(") || self.name.contains(")") || self.name.len()==0 {
            write!(f, "(net {} \"{}\")", self.num, self.name)
        } else {
            write!(f, "(net {} {})", self.num, self.name)
        }
    }
}
impl fmt::Display for NetClass {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(net_class {} {} ", self.name, rustysexp::display_string(&self.desc)));
        try!(write!(f, "(clearance {}) ", self.clearance));
        try!(write!(f, "(trace_width {}) ", self.trace_width));
        try!(write!(f, "(via_dia {}) ", self.via_dia));
        try!(write!(f, "(via_drill {}) ", self.via_drill));
        try!(write!(f, "(uvia_dia {}) ", self.uvia_dia));
        try!(write!(f, "(uvia_drill {}) ", self.uvia_drill));
        for net in &self.nets {
            if net.contains("(") || net.contains(")") {
                try!(write!(f, "(add_net \"{}\")", net))
            } else {
                try!(write!(f, "(add_net {})", net))
            }
        }
        write!(f, ")")

    }
}

impl fmt::Display for Setup {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "(setup"));
        for ref k in &self.elements {
            try!(writeln!(f, "   ({} {})", k.0, k.1));
        }
        match self.pcbplotparams {
            None => writeln!(f, ")"),
            Some(ref s) => writeln!(f, " {})", s),
        }
    }
}

fn parse_version(e:&Sexp) -> ERes<i64> {
    let l = try!(e.slice_atom("version"));
    l[0].i()
}

fn parse_other(e:&Sexp) -> Element {
    let e2 = e.clone();
    Element::Other(e2)
}

fn parse_module(e:&Sexp) -> ERes<Element> {
    let e2 = e.clone();
    let m = try!(footprint::parse_module(e2));
    Ok(Element::Module(m))
}

fn parse_net(e:&Sexp) -> ERes<Element> {
    let l = try!(e.slice_atom("net"));
    let num = try!(l[0].i());
    let name = try!(l[1].string()).clone();
    Ok(Element::Net(Net { name:name, num:num }))
}

fn parse_net_class(e:&Sexp) -> ERes<Element> {
    fn parse(e:&Sexp, name:&str) -> ERes<f64> {
        let l = try!(e.slice_atom(name));
        l[0].f()
    }
    let l = try!(e.slice_atom("net_class"));
    let name = try!(l[0].string()).clone();
    let desc = try!(l[1].string()).clone();
    let mut clearance = 0.1524;
    let mut trace_width = 0.2032;
    let mut via_dia = 0.675;
    let mut via_drill = 0.25;
    let mut uvia_dia = 0.508;
    let mut uvia_drill = 0.127;
    let mut nets = vec![];
    for x in &l[2..] {
        let list_name = try!(x.list_name());
        let xn = &list_name[..];
        match xn {
            "add_net" => {
                let l1 = try!(x.slice_atom("add_net"));
                nets.push(try!(l1[0].string()).clone())
            },
            "clearance" => clearance = try!(parse(x, xn)),
            "trace_width" => trace_width = try!(parse(x, xn)),
            "via_dia" => via_dia = try!(parse(x, xn)),
            "via_drill" => via_drill = try!(parse(x, xn)),
            "uvia_dia" => uvia_dia = try!(parse(x, xn)),
            "uvia_drill" => uvia_drill = try!(parse(x, xn)),
            _ => return Err(format!("unknown net_class field {}", list_name))
        }
    }
    let net_class = NetClass {
        name:name, desc:desc, clearance:clearance, via_dia:via_dia,
        via_drill:via_drill, uvia_dia:uvia_dia, uvia_drill:uvia_drill,
        nets:nets, trace_width:trace_width,
    };
    Ok(Element::NetClass(net_class))
}

fn parse_setup(e:&Sexp) -> ERes<Setup> {
    let mut h = vec![];
    let mut pcbplotparams = None;
    for v in try!(e.slice_atom("setup")) {
        let n = v.list_name().unwrap().clone();
        match &n[..] {
            "pcbplotparams" => { pcbplotparams = Some(v.clone()); },
            x => {
                // TODO: this is a kludge, implement proper data type for Setup
                let v2 = v.slice_atom(x).unwrap();
                let mut s = String::new();
                let mut first = true;
                for z in v2 {
                    if !first { s.push_str(" ") };
                    first = false;
                    s.push_str(z.string().unwrap());
                }
                h.push((n.clone(), s));
            },
        }
    }
    let s = Setup { elements:h , pcbplotparams:pcbplotparams };
    Ok(s)
}

fn parse(s: &str) -> ERes<Layout> {
    let exp = match rustysexp::parse_str(s) {
        Ok(s) => s,
        Err(x) => return Err(format!("ParseError: {}", x)),
    };
    let l1 = try!(exp.slice_atom("kicad_pcb"));
    let mut layout = Layout::new();

    for ref e in l1 {
        match &try!(e.list_name())[..] {
            "version" => layout.version = try!(parse_version(e)),
            "module" => layout.elements.push(try!(parse_module(e))),
            "net" => layout.elements.push(try!(parse_net(e))),
            "net_class" => layout.elements.push(try!(parse_net_class(e))),
            "setup" => layout.setup = try!(parse_setup(e)),
            _ => layout.elements.push(parse_other(e)),
        }
    }
    Ok(layout)
}

pub fn parse_str(s: &str) -> ERes<Layout> {
    parse(s)
}

pub fn parse_file(filename: &PathBuf) -> ERes<Layout> {
    let name = filename.to_str().unwrap();
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => Err(format!("io error: {}", x))
    });
    parse(&s[..])
}
<|endoftext|>


<commit_before>use std::mem;

use rand::{rngs::OsRng, Rng};

use rayon::prelude::*;
use smallvec::SmallVec;

use tile::Faction;

use level::GridLevel;

const LEHMER_MULT0: u128 = 0x9cec0193f9cb55c4acce1fe16e62b05f;
const LEHMER_MULT1: u128 = 0x82163e3e925f6e050dfa28d05eb25d83;
const LEHMER_MULT2: u128 = 0xdd72c15464faa3388de458ec1e58452b;
const LEHMER_MULT3: u128 = 0xb68e8e143dce210d5e40e89d3033fd65;
const LEHMER_MULT4: u128 = 0x12e15e35b500f16e2e714eb2b37916a5;

pub struct FactionGen {
    seed: u128,
}

impl FactionGen {
    pub fn new() -> Self {
        Self {
            seed: OsRng::new().unwrap().gen(),
        }
    }
    #[inline]
    pub fn generate(&mut self, level: &mut GridLevel<Faction>, buffer: &mut GridLevel<Faction>) {
        self.seed = tick(
            self.seed,
            level.get_width(),
            &level.tiles.data[..],
            &mut buffer.tiles.data[..],
        );
        mem::swap(level, buffer);
    }
}

struct CustomRng {
    lehmer1: u128,
    lehmer2: u128,
    lehmer3: u128,
    lehmer4: u128,
}

impl CustomRng {
    fn new(seed: u128) -> Self {
        Self {
            lehmer1: seed << 1 | 1,
            lehmer2: seed << 1 | 1,
            lehmer3: seed << 1 | 1,
            lehmer4: seed << 1 | 1,
        }
    }

    fn gen(&mut self) -> (u64, u64, u64, u64) {
        self.lehmer1 = self.lehmer1.wrapping_mul(LEHMER_MULT0);
        self.lehmer2 = self.lehmer2.wrapping_mul(LEHMER_MULT1);
        self.lehmer3 = self.lehmer3.wrapping_mul(LEHMER_MULT2);
        self.lehmer4 = self.lehmer4.wrapping_mul(LEHMER_MULT3);
        return (
            (self.lehmer1 >> 64) as u64,
            (self.lehmer2 >> 64) as u64,
            (self.lehmer3 >> 64) as u64,
            (self.lehmer4 >> 64) as u64,
        );
    }
}

fn select(deck: &[usize], n: u64) -> usize {
    deck[n as usize % deck.len()]
}

fn index(width: usize, x: i64, y: i64) -> usize {
    (x + y * width as i64) as usize
}

// TODO: Fix this
// TODO: Benchmark this
pub fn tick(seed: u128, width: usize, prev: &[Faction], next: &mut [Faction]) -> u128 {
    let height = prev.len() / width;

    next.par_chunks_mut(width)
        .enumerate()
        .for_each(|(y, chunk)| {
            let mut deck0 = SmallVec::<[_; 9]>::new();
            let mut deck1 = SmallVec::<[_; 9]>::new();
            let mut deck2 = SmallVec::<[_; 9]>::new();
            let mut deck3 = SmallVec::<[_; 9]>::new();
            let mut rng = CustomRng::new(seed ^ (y as u128 * 91));
            for x in (0..height).step_by(4) {
                let (r0, r1, r2, r3) = rng.gen();
                // x x x x x x
                // x o o o o x
                // x x x x x x
                for dy in -1..=1 {
                    for dx in -1..=4 {
                        let xx = x as i64 + dx;
                        let yy = y as i64 + dy;
                        let idx = index(width, xx, yy);
                        if let Some(Faction::Faction(f)) = prev.get(idx) {
                            if dx <= 1 {
                                deck0.push(*f);
                            }
                            if 0 <= dx && dx <= 2 {
                                deck1.push(*f);
                            }
                            if 1 <= dx && dx <= 3 {
                                deck2.push(*f);
                            }
                            if 2 <= dx {
                                deck3.push(*f);
                            }
                        }
                    }
                }

                if !deck0.is_empty() {
                    chunk[x] = Faction::Faction(select(&deck0[..], r0))
                }
                if !deck1.is_empty() {
                    chunk[x + 1] = Faction::Faction(select(&deck1[..], r1));
                }
                if !deck2.is_empty() {
                    chunk[x + 2] = Faction::Faction(select(&deck2[..], r2));
                }
                if !deck3.is_empty() {
                    chunk[x + 3] = Faction::Faction(select(&deck3[..], r3));
                }
                deck0.clear();
                deck1.clear();
                deck2.clear();
                deck3.clear();
            }
        });
    seed.wrapping_mul(LEHMER_MULT4)
}
<commit_msg>Refactoring<commit_after>use std::mem;

use rand::{rngs::OsRng, Rng};

use rayon::prelude::*;
use smallvec::SmallVec;

use tile::Faction;

use level::GridLevel;

const LEHMER_MULT0: u128 = 0x9cec0193f9cb55c4acce1fe16e62b05f;
const LEHMER_MULT1: u128 = 0x82163e3e925f6e050dfa28d05eb25d83;
const LEHMER_MULT2: u128 = 0xdd72c15464faa3388de458ec1e58452b;
const LEHMER_MULT3: u128 = 0xb68e8e143dce210d5e40e89d3033fd65;
const LEHMER_MULT4: u128 = 0x12e15e35b500f16e2e714eb2b37916a5;

pub struct FactionGen {
    seed: u128,
}

impl FactionGen {
    pub fn new() -> Self {
        Self {
            seed: OsRng::new().unwrap().gen::<u128>() << 1 | 1,
        }
    }
    #[inline]
    pub fn generate(&mut self, level: &mut GridLevel<Faction>, buffer: &mut GridLevel<Faction>) {
        self.seed = tick(
            self.seed,
            level.get_width(),
            &level.tiles.data[..],
            &mut buffer.tiles.data[..],
        );
        mem::swap(level, buffer);
    }
}

struct LehmerRng {
    lehmer: u128,
    mult: u128,
}

impl LehmerRng {
    fn new(seed: u128, mult: u128) -> Self {
        Self {
            lehmer: seed << 1 | 1,
            mult,
        }
    }

    fn gen(&mut self) -> u64 {
        self.lehmer = self.lehmer.wrapping_mul(self.mult);
        return (self.lehmer >> 64) as u64;
    }
}

fn select(deck: &[usize], n: u64) -> usize {
    deck[n as usize % deck.len()]
}

fn index(width: usize, x: i64, y: i64) -> usize {
    (x + y * width as i64) as usize
}

fn mix(a: u128, b: usize, mult: u128) -> u128 {
    a ^ ((b << 1 | 1) as u128).wrapping_mul(mult)
}

pub fn tick(seed: u128, width: usize, prev: &[Faction], next: &mut [Faction]) -> u128 {
    const FACTOR: usize = 4;
    let height = prev.len() / width;
    let corrected = (height / FACTOR) * FACTOR;

    next.par_chunks_mut(width)
        .enumerate()
        .for_each(|(y, chunk)| {
            let mut deck0 = SmallVec::<[_; 9]>::new();
            let mut deck1 = SmallVec::<[_; 9]>::new();
            let mut deck2 = SmallVec::<[_; 9]>::new();
            let mut deck3 = SmallVec::<[_; 9]>::new();
            let mut rng0 = LehmerRng::new(mix(seed, y, LEHMER_MULT0), LEHMER_MULT0);
            let mut rng1 = LehmerRng::new(mix(seed, y, LEHMER_MULT1), LEHMER_MULT1);
            let mut rng2 = LehmerRng::new(mix(seed, y, LEHMER_MULT2), LEHMER_MULT2);
            let mut rng3 = LehmerRng::new(mix(seed, y, LEHMER_MULT3), LEHMER_MULT3);
            let mut calc = |x, deck: &mut SmallVec<[_; 9]>, n| {
                if !deck.is_empty() {
                    let f = select(&deck[..], n);
                    chunk[x] = Faction::Faction(f);
                    deck.clear();
                }
            };
            for x in (0..corrected).step_by(FACTOR) {
                // x x x x x x
                // x o o o o x
                // x x x x x x
                for dy in -1..=1 {
                    for dx in -1..=(FACTOR as i64) {
                        let xx = x as i64 + dx;
                        let yy = y as i64 + dy;
                        let idx = index(width, xx, yy);
                        if let Some(Faction::Faction(f)) = prev.get(idx) {
                            if dx <= 1 {
                                deck0.push(*f);
                            }
                            if 0 <= dx && dx <= 2 {
                                deck1.push(*f);
                            }
                            if 1 <= dx && dx <= 3 {
                                deck2.push(*f);
                            }
                            if 2 <= dx {
                                deck3.push(*f);
                            }
                        }
                    }
                }
                calc(x + 0, &mut deck0, rng0.gen());
                calc(x + 1, &mut deck1, rng1.gen());
                calc(x + 2, &mut deck2, rng2.gen());
                calc(x + 3, &mut deck3, rng3.gen());
            }
            for x in corrected..height {
                for dy in -1..=1 {
                    for dx in -1..=1 {
                        let xx = x as i64 + dx;
                        let yy = y as i64 + dy;
                        let idx = index(width, xx, yy);
                        if let Some(Faction::Faction(f)) = prev.get(idx) {
                            deck0.push(*f);
                        }
                    }
                }
                calc(x, &mut deck0, rng0.gen());
            }
        });
    seed.wrapping_mul(LEHMER_MULT4)
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// 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 backend::StoreBackend;
use key;
use std::error::Error;
use std::fs;
use std::io;
use std::path::PathBuf;
use std::str;
use std::sync::{Mutex, atomic};
use time;
use util::{FileIterator, PathHandler, SyncPool};

struct FileEntry {
    key_entry: key::Entry,
    metadata: fs::Metadata,
    full_path: PathBuf,
}

impl FileEntry {
    fn new(full_path: PathBuf, parent: Option<u64>) -> Result<FileEntry, Box<Error>> {
        debug!("FileEntry::new({:?})", full_path);

        let filename_opt = full_path.file_name().and_then(|n| n.to_str()).map(|n| {
            n.bytes().collect()
        });

        if filename_opt.is_some() {
            let meta = fs::symlink_metadata(&full_path)?;
            let data = if meta.is_file() {
                key::Data::FilePlaceholder
            } else if meta.is_dir() {
                key::Data::DirPlaceholder
            } else if meta.file_type().is_symlink() {
                let path = fs::read_link(&full_path)?;
                key::Data::Symlink(path)
            } else {
                // Unsupported file type. Skipping.
                return Err(From::from(format!("unknown file kind")));
            };
            Ok(FileEntry {
                key_entry: key::Entry::new(parent, filename_opt.unwrap(), data, Some(&meta)),
                metadata: meta,
                full_path: full_path,
            })
        } else {
            Err(From::from("Could not parse filename."[..].to_owned()))
        }
    }

    fn is_file(&self) -> bool {
        self.metadata.is_file()
    }
    fn is_directory(&self) -> bool {
        self.metadata.is_dir()
    }
}

pub struct InsertPathHandler<B: StoreBackend> {
    count: atomic::AtomicIsize,
    last_print: Mutex<time::Timespec>,
    key_store: SyncPool<key::StoreProcess<FileIterator, B>>,
}

impl<B: StoreBackend> InsertPathHandler<B> {
    pub fn new(key_stores: Vec<key::StoreProcess<FileIterator, B>>) -> InsertPathHandler<B> {
        InsertPathHandler {
            count: atomic::AtomicIsize::new(0),
            last_print: Mutex::new(time::now().to_timespec()),
            key_store: SyncPool::new(key_stores),
        }
    }
}

impl<B: StoreBackend> PathHandler<Option<u64>> for InsertPathHandler<B> {
    type DirItem = fs::DirEntry;
    type DirIter = fs::ReadDir;

    fn read_dir(&self, path: &PathBuf) -> io::Result<Self::DirIter> {
        fs::read_dir(path)
    }

    fn handle_path(&self, parent: &Option<u64>, path: &PathBuf) -> Option<Option<u64>> {
        let count = self.count.fetch_add(1, atomic::Ordering::SeqCst) + 1;

        if count % 16 == 0 {
            // don't hammer the mutex
            let mut guarded_last_print = self.last_print.lock().unwrap();
            let now = time::now().to_timespec();
            if guarded_last_print.sec <= now.sec - 1 {
                println!("#{}: {}", count, path.display());
                *guarded_last_print = now;
            }
        }

        match FileEntry::new(path.clone(), *parent) {
            Err(e) => {
                println!("Skipping '{}': {}", path.display(), e);
            }
            Ok(file_entry) => {
                let is_file = file_entry.is_file();
                let is_directory = file_entry.is_directory();
                let local_root = path.clone();
                let full_path = file_entry.full_path.clone();

                let ks = self.key_store.lock().unwrap();
                match ks.send_reply(key::Msg::Insert(
                    file_entry.key_entry,
                    if is_file {
                        Some(Box::new(move |()| {
                        match FileIterator::new(&full_path) {
                            Err(e) => {
                                println!("Skipping '{}': {}", local_root.display(), e.to_string());
                                None
                            }
                            Ok(it) => Some(it),
                        }
                    }))
                    } else {
                        None
                    },
                )) {
                    Ok(key::Reply::Id(id)) => {
                        if is_directory {
                            return Some(Some(id));
                        }
                    }
                    Err(e) => panic!("Error from key store: {:?}", e),
                    _ => panic!("Unexpected reply from key store."),
                }
            }
        }

        None
    }
}
<commit_msg>Minor: simplication<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// 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 backend::StoreBackend;
use key;
use std::error::Error;
use std::fs;
use std::io;
use std::path::PathBuf;
use std::str;
use std::sync::{Mutex, atomic};
use time;
use util::{FileIterator, PathHandler, SyncPool};

struct FileEntry {
    key_entry: key::Entry,
    metadata: fs::Metadata,
    full_path: PathBuf,
}

impl FileEntry {
    fn new(full_path: PathBuf, parent: Option<u64>) -> Result<FileEntry, Box<Error>> {
        debug!("FileEntry::new({:?})", full_path);

        let filename_opt = full_path.file_name().and_then(|n| n.to_str()).map(|s| {
            s.as_bytes().to_vec()
        });

        if let Some(filename) = filename_opt {
            let meta = fs::symlink_metadata(&full_path)?;
            let data = if meta.is_file() {
                key::Data::FilePlaceholder
            } else if meta.is_dir() {
                key::Data::DirPlaceholder
            } else if meta.file_type().is_symlink() {
                let path = fs::read_link(&full_path)?;
                key::Data::Symlink(path)
            } else {
                // Unsupported file type. Skipping.
                return Err(From::from(format!("unknown file kind")));
            };
            Ok(FileEntry {
                key_entry: key::Entry::new(parent, filename, data, Some(&meta)),
                metadata: meta,
                full_path: full_path,
            })
        } else {
            Err(From::from("Could not parse filename."[..].to_owned()))
        }
    }

    fn is_file(&self) -> bool {
        self.metadata.is_file()
    }
    fn is_directory(&self) -> bool {
        self.metadata.is_dir()
    }
}

pub struct InsertPathHandler<B: StoreBackend> {
    count: atomic::AtomicIsize,
    last_print: Mutex<time::Timespec>,
    key_store: SyncPool<key::StoreProcess<FileIterator, B>>,
}

impl<B: StoreBackend> InsertPathHandler<B> {
    pub fn new(key_stores: Vec<key::StoreProcess<FileIterator, B>>) -> InsertPathHandler<B> {
        InsertPathHandler {
            count: atomic::AtomicIsize::new(0),
            last_print: Mutex::new(time::now().to_timespec()),
            key_store: SyncPool::new(key_stores),
        }
    }
}

impl<B: StoreBackend> PathHandler<Option<u64>> for InsertPathHandler<B> {
    type DirItem = fs::DirEntry;
    type DirIter = fs::ReadDir;

    fn read_dir(&self, path: &PathBuf) -> io::Result<Self::DirIter> {
        fs::read_dir(path)
    }

    fn handle_path(&self, parent: &Option<u64>, path: &PathBuf) -> Option<Option<u64>> {
        let count = self.count.fetch_add(1, atomic::Ordering::SeqCst) + 1;

        if count % 16 == 0 {
            // don't hammer the mutex
            let mut guarded_last_print = self.last_print.lock().unwrap();
            let now = time::now().to_timespec();
            if guarded_last_print.sec <= now.sec - 1 {
                println!("#{}: {}", count, path.display());
                *guarded_last_print = now;
            }
        }

        match FileEntry::new(path.clone(), *parent) {
            Err(e) => {
                println!("Skipping '{}': {}", path.display(), e);
            }
            Ok(file_entry) => {
                let is_file = file_entry.is_file();
                let is_directory = file_entry.is_directory();
                let local_root = path.clone();
                let full_path = file_entry.full_path.clone();

                let ks = self.key_store.lock().unwrap();
                match ks.send_reply(key::Msg::Insert(
                    file_entry.key_entry,
                    if is_file {
                        Some(Box::new(move |()| {
                        match FileIterator::new(&full_path) {
                            Err(e) => {
                                println!("Skipping '{}': {}", local_root.display(), e.to_string());
                                None
                            }
                            Ok(it) => Some(it),
                        }
                    }))
                    } else {
                        None
                    },
                )) {
                    Ok(key::Reply::Id(id)) => {
                        if is_directory {
                            return Some(Some(id));
                        }
                    }
                    Err(e) => panic!("Error from key store: {:?}", e),
                    _ => panic!("Unexpected reply from key store."),
                }
            }
        }

        None
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use error::{ Result, EngineError, TemplateError };

pub trait Loader {
    fn get_source(&self, name: &str) -> Result<String>;
}

#[derive(Debug)]
pub struct ArrayLoader {
    files: HashMap<String, String>,
}

impl ArrayLoader {
    pub fn new(sources: HashMap<String, String>) -> ArrayLoader {
        ArrayLoader {
            files: sources,
        }
    }
}

impl Loader for ArrayLoader {
    fn get_source(&self, name: &str) -> Result<String> {
        match self.files.get(name) {
            Some(contents) => Ok(contents.clone()),
            None => Err(EngineError::TemplateNotFound {
                name: name.into(),
                search_paths: Vec::new()
            }.caused_by(
                TemplateError::UnexpectedEndOfTemplate.at(0).into()
            ).into()),
        }
    }
}
<commit_msg>Remove test cause.<commit_after>use std::collections::HashMap;
use error::{ Result, EngineError };

pub trait Loader {
    fn get_source(&self, name: &str) -> Result<String>;
}

#[derive(Debug)]
pub struct ArrayLoader {
    files: HashMap<String, String>,
}

impl ArrayLoader {
    pub fn new(sources: HashMap<String, String>) -> ArrayLoader {
        ArrayLoader {
            files: sources,
        }
    }
}

impl Loader for ArrayLoader {
    fn get_source(&self, name: &str) -> Result<String> {
        match self.files.get(name) {
            Some(contents) => Ok(contents.clone()),
            None => Err(EngineError::TemplateNotFound {
                name: name.into(),
                search_paths: Vec::new()
            }.into()),
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * 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.
 */

include!("../relm-state/src/macros.rs");
<commit_msg>Temporary fix to publish the crate<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * 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.
 */

/// Connect events to sending a message.
///
/// ## Rules
/// 1. Send `$msg` to `$other_component` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Optionally send `$msg.0` when the GTK+ `$event` is emitted on `$widget`.
/// Return `$msg.1` in the GTK+ callback.
/// This variant gives more control to the caller since it expects a `$msg` returning `(Option<MSG>,
/// ReturnValue)` where the `ReturnValue` is the value to return in the GTK+ callback.
/// Option<MSG> can be None if no message needs to be emitted.
///
/// 3. Send `$msg` when the GTK+ `$event` is emitted on `$widget`.
///
/// 4. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect {
    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_component:expr, $msg:expr) => {
        connect_stream!($widget, $event($($args),*), $other_component.stream(), $msg);
    };

    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), return $msg:expr) => {{
        connect_stream!(return $relm.stream(), $widget, $event($($args),*), $msg);
    }};

    // Connect to a GTK+ widget event.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $relm.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    }};

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_component:ident @ $message:pat, $dst_component:expr, $msg:expr) => {
        let stream = $src_component.stream().clone();
        connect_stream!(stream@$message, $dst_component.stream(), $msg);
    };
}

/// Connect events to sending a message.
/// Similar to `connect!` but wants a stream instead of a component.
///
/// ## Rules
/// 1. Send `$msg` to `$other_stream` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect_stream {
    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    (return $stream:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let (msg, return_value) = $crate::IntoPair::into_pair($msg);
            let msg: Option<_> = $crate::IntoOption::into_option(msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
            return_value
        });
    }};

    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_stream:expr, $msg:expr) => {
        let stream = $other_stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    };

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_stream:ident @ $message:pat, $dst_stream:expr, $msg:expr) => {
        let stream = $dst_stream.clone();
        $src_stream.observe(move |msg| {
            #[allow(unreachable_patterns)]
            match msg {
                &$message =>  {
                    let msg: Option<_> = $crate::IntoOption::into_option($msg);
                    if let Some(msg) = msg {
                        stream.emit(msg);
                    }
                },
                _ => (),
            }
        });
    };
}

/// Connect an asynchronous method call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let stream = $relm.stream().clone();
        $object.$async_method($($args,)* None, move |result| {
            if let Ok(result) = result {
                stream.emit($msg(result));
            }
        });
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        $object.$async_method($($args,)* None, move |result| {
            match result {
                Ok(value) => event_stream.emit($msg(value)),
                Err(error) => fail_event_stream.emit($fail_msg(error)),
            }
        });
    }};
}

/// Connect an asynchronous function call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async_func {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let stream = $relm.stream().clone();
        $class::$async_func($($args,)* None, move |result| {
            if let Ok(result) = result {
                stream.emit($msg(result));
            }
        });
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        $class::$async_func($($args,)* None, move |result| {
            match result {
                Ok(value) => event_stream.emit($msg(value)),
                Err(error) => fail_event_stream.emit($fail_msg(error)),
            }
        });

    }};
}

/// Like `connect_async!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_full {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = $relm.stream().clone();
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.emit($msg(result));
            }
        });
        cancellable
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.emit($msg(value)),
                Err(error) => fail_event_stream.emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}

/// Like `connect_async_func!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_func_full {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async!($async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = $relm.stream().clone();
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.emit($msg(result));
            }
        });
        cancellable
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.emit($msg(value)),
                Err(error) => fail_event_stream.emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * 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.
 */

include!("../relm-state/src/macros.rs");
<commit_msg>Temporary fix to publish the crate<commit_after>/*
 * Copyright (c) 2017-2019 Boucher, Antoni <bouanto@zoho.com>
 *
 * 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.
 */

/// Connect events to sending a message.
///
/// ## Rules
/// 1. Send `$msg` to `$other_component` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Optionally send `$msg.0` when the GTK+ `$event` is emitted on `$widget`.
/// Return `$msg.1` in the GTK+ callback.
/// This variant gives more control to the caller since it expects a `$msg` returning `(Option<MSG>,
/// ReturnValue)` where the `ReturnValue` is the value to return in the GTK+ callback.
/// Option<MSG> can be None if no message needs to be emitted.
///
/// 3. Send `$msg` when the GTK+ `$event` is emitted on `$widget`.
///
/// 4. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect {
    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_component:expr, $msg:expr) => {
        connect_stream!($widget, $event($($args),*), $other_component.stream(), $msg);
    };

    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), return $msg:expr) => {{
        connect_stream!(return $relm.stream(), $widget, $event($($args),*), $msg);
    }};

    // Connect to a GTK+ widget event.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $relm.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    }};

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_component:ident @ $message:pat, $dst_component:expr, $msg:expr) => {
        let stream = $src_component.stream().clone();
        connect_stream!(stream@$message, $dst_component.stream(), $msg);
    };
}

/// Connect events to sending a message.
/// Similar to `connect!` but wants a stream instead of a component.
///
/// ## Rules
/// 1. Send `$msg` to `$other_stream` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect_stream {
    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    (return $stream:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let (msg, return_value) = $crate::IntoPair::into_pair($msg);
            let msg: Option<_> = $crate::IntoOption::into_option(msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
            return_value
        });
    }};

    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_stream:expr, $msg:expr) => {
        let stream = $other_stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    };

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_stream:ident @ $message:pat, $dst_stream:expr, $msg:expr) => {
        let stream = $dst_stream.clone();
        $src_stream.observe(move |msg| {
            #[allow(unreachable_patterns)]
            match msg {
                &$message =>  {
                    let msg: Option<_> = $crate::IntoOption::into_option($msg);
                    if let Some(msg) = msg {
                        stream.emit(msg);
                    }
                },
                _ => (),
            }
        });
    };
}

/// Connect an asynchronous method call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        // TODO: remove any use of Fragile when gio callbacks stop requiring Send.
        let stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* None, move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        let fail_event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* None, move |result| {
            match result.into_inner() {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });
    }};
}

/// Connect an asynchronous function call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async_func {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* None, move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        let fail_event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* None, move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

    }};
}

/// Like `connect_async!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_full {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
        cancellable
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        let fail_event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}

/// Like `connect_async_func!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_func_full {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async!($async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
        cancellable
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        let fail_event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}
<|endoftext|>


<commit_before>//! This module provides two utility macros for testing custom derives. They can
//! be used together to eliminate some of the boilerplate required in order to
//! declare and test custom derive implementations.

// Re-exports used by the decl_derive! and test_derive!
pub use syn::{parse_str, parse, DeriveInput};
pub use quote::Tokens;
pub use proc_macro::TokenStream as TokenStream;
pub use proc_macro2::TokenStream as TokenStream2;

/// The `decl_derive!` macro declares a custom derive wrapper. It will parse the
/// incoming `TokenStream` into a `synstructure::Structure` object, and pass it
/// into the inner function.
///
/// Your inner function should have the following type:
///
/// ```
/// # extern crate quote;
/// # extern crate synstructure;
/// fn derive(input: synstructure::Structure) -> quote::Tokens {
///     unimplemented!()
/// }
/// ```
///
/// # Usage
///
/// ### Without Attributes
/// ```
/// # #[macro_use] extern crate quote;
/// # extern crate synstructure;
/// # fn main() {}
/// fn derive_interesting(_input: synstructure::Structure) -> quote::Tokens {
///     quote! { ... }
/// }
///
/// # const _IGNORE: &'static str = stringify! {
/// decl_derive!([Interesting] => derive_interesting);
/// # };
/// ```
///
/// ### With Attributes
/// ```
/// # #[macro_use] extern crate quote;
/// # extern crate synstructure;
/// # fn main() {}
/// fn derive_interesting(_input: synstructure::Structure) -> quote::Tokens {
///     quote! { ... }
/// }
///
/// # const _IGNORE: &'static str = stringify! {
/// decl_derive!([Interesting, attributes(interesting_ignore)] => derive_interesting);
/// # };
/// ```
#[macro_export]
macro_rules! decl_derive {
    // XXX: Switch to using this variant everywhere?
    ([$derives:ident $($derive_t:tt)*] => $inner:path) => {
        #[proc_macro_derive($derives $($derive_t)*)]
        #[allow(non_snake_case)]
        pub fn $derives(
            i: $crate::macros::TokenStream
        ) -> $crate::macros::TokenStream
        {
            let parsed = $crate::macros::parse::<$crate::macros::DeriveInput>(i)
                .expect(concat!("Failed to parse input to `#[derive(",
                                stringify!($derives),
                                ")]`"));
            $inner($crate::Structure::new(&parsed)).into()
        }
    };
}

/// Run a test on a custom derive. This macro expands both the original struct
/// and the expansion to ensure that they compile correctly, and confirms that
/// feeding the original struct into the named derive will produce the written
/// output.
///
/// You can add `no_build` to the end of the macro invocation to disable
/// checking that the written code compiles. This is useful in contexts where
/// the procedural macro cannot depend on the crate where it is used during
/// tests.
///
/// # Usage
///
/// ```
/// # #[macro_use] extern crate quote;
/// # #[macro_use] extern crate synstructure;
/// fn test_derive_example(_s: synstructure::Structure) -> quote::Tokens {
///     quote! { const YOUR_OUTPUT: &'static str = "here"; }
/// }
///
/// fn main() {
///     test_derive!{
///         test_derive_example {
///             struct A;
///         }
///         expands to {
///             const YOUR_OUTPUT: &'static str = "here";
///         }
///     }
/// }
/// ```
#[macro_export]
macro_rules! test_derive {
    ($name:path { $($i:tt)* } expands to { $($o:tt)* }) => {
        {
            #[allow(dead_code)]
            fn ensure_compiles() {
                $($i)*
                $($o)*
            }

            test_derive!($name { $($i)* } expands to { $($o)* } no_build);
        }
    };

    ($name:path { $($i:tt)* } expands to { $($o:tt)* } no_build) => {
        {
            let i = stringify!( $($i)* );
            let parsed = $crate::macros::parse_str::<$crate::macros::DeriveInput>(i)
                .expect(concat!("Failed to parse input to `#[derive(",
                                stringify!($name),
                                ")]`"));

            let res = $name($crate::Structure::new(&parsed));
            let expected = stringify!( $($o)* )
                .parse::<$crate::macros::TokenStream2>()
                .expect("output should be a valid TokenStream");
            let mut expected_toks = $crate::macros::Tokens::new();
            expected_toks.append_all(expected);

            if res != expected_toks {
                panic!("\
test_derive failed:
expected:
```
{}
```

got:
```
{}
```\n",
                    $crate::unpretty_print(&expected_toks),
                    $crate::unpretty_print(&res),
                );
            }
            // assert_eq!(res, expected_toks)
        }
    };
}

/// A helper macro for declaring relatively straightforward derive
/// implementations. It provides mechanisms for operating over structures
/// performing modifications on each field etc.
///
/// This macro doesn't define the actual derive, but rather the implementation
/// method. Use `decl_derive!` to generate the implementation wrapper.
///
/// # Stability Warning
///
/// This is an unstable experimental macro API, which may be changed or removed
/// in a future version. I'm not yet confident enough that this API is useful
/// enough to warrant its complexity and inclusion in `synstructure`.
///
/// # Caveat
///
/// The `quote!` macro from `quote` must be imported in the calling crate, as
/// this macro depends on it.
///
/// # Note
///
/// This feature is implemented behind the `simple-derive` feature, and is only
/// avaliable when that feature is enabled.
///
/// # Example
///
/// ```
/// #[macro_use]
/// extern crate quote;
/// #[macro_use]
/// extern crate synstructure;
/// # const _IGNORE: &'static str = stringify! {
/// decl_derive!([Interest] => derive_interest);
/// # };
///
/// simple_derive! {
///     // This macro implements the `Interesting` method exported by the `aa`
///     // crate. It will explicitly add an `extern crate` invocation to import the
///     // crate into the expanded context.
///     derive_interest impl synstructure_test_traits::Interest {
///         // A "filter" block can be added. It evaluates its body with the (s)
///         // variable bound to a mutable reference to the input `Structure`
///         // object.
///         //
///         // This block can be used to perform general transformations, such as
///         // filtering out fields which should be ignored by all methods and for
///         // the purposes of binding type parameters.
///         filter(s) {
///             s.filter(|bi| bi.ast().ident != Some("a".into()));
///         }
///
///         // This is an implementation of a method in the implemented crate. The
///         // return value should be the series of match patterns to destructure
///         // the `self` argument with.
///         fn interesting(&self as s) -> bool {
///             s.fold(false, |acc, bi| {
///                 quote!(#acc || synstructure_test_traits::Interest::interesting(#bi))
///             })
///         }
///     }
/// }
///
/// fn main() {
///     test_derive!{
///         derive_interest {
///             struct A<T> {
///                 x: i32,
///                 a: bool, // Will be ignored by filter
///                 c: T,
///             }
///         }
///         expands to {
///             #[allow(non_upper_case_globals)]
///             const _DERIVE_synstructure_test_traits_Interest_FOR_A: () = {
///                 extern crate synstructure_test_traits;
///                 impl<T> synstructure_test_traits::Interest for A<T>
///                     where T: synstructure_test_traits::Interest
///                 {
///                     fn interesting(&self) -> bool {
///                         match *self {
///                             A {
///                                 x: ref __binding_0,
///                                 c: ref __binding_2,
///                                 ..
///                             } => {
///                                 false ||
///                                     synstructure_test_traits::Interest::interesting(__binding_0) ||
///                                     synstructure_test_traits::Interest::interesting(__binding_2)
///                             }
///                         }
///                     }
///                 }
///             };
///         }
///     }
/// }
/// ```
#[cfg(feature = "simple-derive")]
#[macro_export]
macro_rules! simple_derive {
    // entry point
    (
        $iname:ident impl $path:path { $($rest:tt)* }
    ) => {
        simple_derive!(@I [$iname, $path] { $($rest)* } [] []);
    };

    // Adding a filter block
    (
        @I $opt:tt {
            filter($s:ident) {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            @I $opt { $($rest)* } [$($done)*] [
                $($filter)*
                [
                    st_name = $s,
                    body = {
                        $($body)*
                    },
                ]
            ]
        );
    };

    // &self bound method
    (
        @I $opt:tt {
            fn $fn_name:ident (&self as $s:ident $($params:tt)*) $(-> $t:ty)* {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            @I $opt { $($rest)* } [
                $($done)*
                [
                    st_name = $s,
                    bind_style = Ref,
                    body = { $($body)* },
                    result = result,
                    expanded = {
                        fn $fn_name(&self $($params)*) $(-> $t)* {
                            match *self { #result }
                        }
                    },
                ]
            ] [$($filter)*]
        );
    };

    // &mut self bound method
    (
        @I $opt:tt {
            fn $fn_name:ident (&mut self as $s:ident $($params:tt)*) $(-> $t:ty)* {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            @I $opt { $($rest)* } [
                $($done)*
                [
                    st_name = $s,
                    bind_style = RefMut,
                    body = { $($body)* },
                    result = result,
                    expanded = {
                        fn $fn_name(&mut self $($params)*) $(-> $t)* {
                            match *self { #result }
                        }
                    },
                ]
            ] [$($filter)*]
        );
    };

    // self bound method
    (
        @I $opt:tt {
            fn $fn_name:ident (self as $s:ident $($params:tt)*) $(-> $t:ty)* {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            @I $opt { $($rest)* } [
                $($done)*
                [
                    st_name = $s,
                    bind_style = Move,
                    body = { $($body)* },
                    result = result,
                    expanded = {
                        fn $fn_name(self $($params)*) $(-> $t)* {
                            match self { #result }
                        }
                    },
                ]
            ] [$($filter)*]
        );
    };

    // XXX: Static methods?

    // codegen after data collection
    (
        @I [$iname:ident, $path:path] {} [$(
            [
                st_name = $st_name:ident,
                bind_style = $bind_style:ident,
                body = $body:tt,
                result = $result:ident,
                expanded = { $($expanded:tt)* },
            ]
        )*] [$(
            [
                st_name = $filter_st_name:ident,
                body = $filter_body:tt,
            ]
        )*]
    ) => {
        fn $iname(mut st: $crate::Structure) -> $crate::macros::Tokens {
            let _ = &mut st; // Silence the unused mut warning

            // Filter/transform the `Structure` object before cloning it for
            // individual methods.
            $(
                {
                    let $filter_st_name = &mut st;
                    $filter_body
                }
            )*

            // Clone the `Structure` object and set the correct binding style,
            // then perform method specific expansion.
            $(
                let $result = {
                    let mut $st_name = st.clone();
                    $st_name.bind_with(|_| ::synstructure::BindStyle::$bind_style);
                    let $result = {
                        $body
                    };
                    quote!{ $($expanded)* }
                };
            )*

            st.bound_impl(quote!($path), quote!{
                $(#$result)*
            })
        }
    }
}
<commit_msg>Use identifiers to denote internal macro patterns<commit_after>//! This module provides two utility macros for testing custom derives. They can
//! be used together to eliminate some of the boilerplate required in order to
//! declare and test custom derive implementations.

// Re-exports used by the decl_derive! and test_derive!
pub use syn::{parse_str, parse, DeriveInput};
pub use quote::Tokens;
pub use proc_macro::TokenStream as TokenStream;
pub use proc_macro2::TokenStream as TokenStream2;

/// The `decl_derive!` macro declares a custom derive wrapper. It will parse the
/// incoming `TokenStream` into a `synstructure::Structure` object, and pass it
/// into the inner function.
///
/// Your inner function should have the following type:
///
/// ```
/// # extern crate quote;
/// # extern crate synstructure;
/// fn derive(input: synstructure::Structure) -> quote::Tokens {
///     unimplemented!()
/// }
/// ```
///
/// # Usage
///
/// ### Without Attributes
/// ```
/// # #[macro_use] extern crate quote;
/// # extern crate synstructure;
/// # fn main() {}
/// fn derive_interesting(_input: synstructure::Structure) -> quote::Tokens {
///     quote! { ... }
/// }
///
/// # const _IGNORE: &'static str = stringify! {
/// decl_derive!([Interesting] => derive_interesting);
/// # };
/// ```
///
/// ### With Attributes
/// ```
/// # #[macro_use] extern crate quote;
/// # extern crate synstructure;
/// # fn main() {}
/// fn derive_interesting(_input: synstructure::Structure) -> quote::Tokens {
///     quote! { ... }
/// }
///
/// # const _IGNORE: &'static str = stringify! {
/// decl_derive!([Interesting, attributes(interesting_ignore)] => derive_interesting);
/// # };
/// ```
#[macro_export]
macro_rules! decl_derive {
    // XXX: Switch to using this variant everywhere?
    ([$derives:ident $($derive_t:tt)*] => $inner:path) => {
        #[proc_macro_derive($derives $($derive_t)*)]
        #[allow(non_snake_case)]
        pub fn $derives(
            i: $crate::macros::TokenStream
        ) -> $crate::macros::TokenStream
        {
            let parsed = $crate::macros::parse::<$crate::macros::DeriveInput>(i)
                .expect(concat!("Failed to parse input to `#[derive(",
                                stringify!($derives),
                                ")]`"));
            $inner($crate::Structure::new(&parsed)).into()
        }
    };
}

/// Run a test on a custom derive. This macro expands both the original struct
/// and the expansion to ensure that they compile correctly, and confirms that
/// feeding the original struct into the named derive will produce the written
/// output.
///
/// You can add `no_build` to the end of the macro invocation to disable
/// checking that the written code compiles. This is useful in contexts where
/// the procedural macro cannot depend on the crate where it is used during
/// tests.
///
/// # Usage
///
/// ```
/// # #[macro_use] extern crate quote;
/// # #[macro_use] extern crate synstructure;
/// fn test_derive_example(_s: synstructure::Structure) -> quote::Tokens {
///     quote! { const YOUR_OUTPUT: &'static str = "here"; }
/// }
///
/// fn main() {
///     test_derive!{
///         test_derive_example {
///             struct A;
///         }
///         expands to {
///             const YOUR_OUTPUT: &'static str = "here";
///         }
///     }
/// }
/// ```
#[macro_export]
macro_rules! test_derive {
    ($name:path { $($i:tt)* } expands to { $($o:tt)* }) => {
        {
            #[allow(dead_code)]
            fn ensure_compiles() {
                $($i)*
                $($o)*
            }

            test_derive!($name { $($i)* } expands to { $($o)* } no_build);
        }
    };

    ($name:path { $($i:tt)* } expands to { $($o:tt)* } no_build) => {
        {
            let i = stringify!( $($i)* );
            let parsed = $crate::macros::parse_str::<$crate::macros::DeriveInput>(i)
                .expect(concat!("Failed to parse input to `#[derive(",
                                stringify!($name),
                                ")]`"));

            let res = $name($crate::Structure::new(&parsed));
            let expected = stringify!( $($o)* )
                .parse::<$crate::macros::TokenStream2>()
                .expect("output should be a valid TokenStream");
            let mut expected_toks = $crate::macros::Tokens::new();
            expected_toks.append_all(expected);

            if res != expected_toks {
                panic!("\
test_derive failed:
expected:
```
{}
```

got:
```
{}
```\n",
                    $crate::unpretty_print(&expected_toks),
                    $crate::unpretty_print(&res),
                );
            }
            // assert_eq!(res, expected_toks)
        }
    };
}

/// A helper macro for declaring relatively straightforward derive
/// implementations. It provides mechanisms for operating over structures
/// performing modifications on each field etc.
///
/// This macro doesn't define the actual derive, but rather the implementation
/// method. Use `decl_derive!` to generate the implementation wrapper.
///
/// # Stability Warning
///
/// This is an unstable experimental macro API, which may be changed or removed
/// in a future version. I'm not yet confident enough that this API is useful
/// enough to warrant its complexity and inclusion in `synstructure`.
///
/// # Caveat
///
/// The `quote!` macro from `quote` must be imported in the calling crate, as
/// this macro depends on it.
///
/// # Note
///
/// This feature is implemented behind the `simple-derive` feature, and is only
/// avaliable when that feature is enabled.
///
/// # Example
///
/// ```
/// #[macro_use]
/// extern crate quote;
/// #[macro_use]
/// extern crate synstructure;
/// # const _IGNORE: &'static str = stringify! {
/// decl_derive!([Interest] => derive_interest);
/// # };
///
/// simple_derive! {
///     // This macro implements the `Interesting` method exported by the `aa`
///     // crate. It will explicitly add an `extern crate` invocation to import the
///     // crate into the expanded context.
///     derive_interest impl synstructure_test_traits::Interest {
///         // A "filter" block can be added. It evaluates its body with the (s)
///         // variable bound to a mutable reference to the input `Structure`
///         // object.
///         //
///         // This block can be used to perform general transformations, such as
///         // filtering out fields which should be ignored by all methods and for
///         // the purposes of binding type parameters.
///         filter(s) {
///             s.filter(|bi| bi.ast().ident != Some("a".into()));
///         }
///
///         // This is an implementation of a method in the implemented crate. The
///         // return value should be the series of match patterns to destructure
///         // the `self` argument with.
///         fn interesting(&self as s) -> bool {
///             s.fold(false, |acc, bi| {
///                 quote!(#acc || synstructure_test_traits::Interest::interesting(#bi))
///             })
///         }
///     }
/// }
///
/// fn main() {
///     test_derive!{
///         derive_interest {
///             struct A<T> {
///                 x: i32,
///                 a: bool, // Will be ignored by filter
///                 c: T,
///             }
///         }
///         expands to {
///             #[allow(non_upper_case_globals)]
///             const _DERIVE_synstructure_test_traits_Interest_FOR_A: () = {
///                 extern crate synstructure_test_traits;
///                 impl<T> synstructure_test_traits::Interest for A<T>
///                     where T: synstructure_test_traits::Interest
///                 {
///                     fn interesting(&self) -> bool {
///                         match *self {
///                             A {
///                                 x: ref __binding_0,
///                                 c: ref __binding_2,
///                                 ..
///                             } => {
///                                 false ||
///                                     synstructure_test_traits::Interest::interesting(__binding_0) ||
///                                     synstructure_test_traits::Interest::interesting(__binding_2)
///                             }
///                         }
///                     }
///                 }
///             };
///         }
///     }
/// }
/// ```
#[cfg(feature = "simple-derive")]
#[macro_export]
macro_rules! simple_derive {
    // entry point
    (
        $iname:ident impl $path:path { $($rest:tt)* }
    ) => {
        simple_derive!(__I [$iname, $path] { $($rest)* } [] []);
    };

    // Adding a filter block
    (
        __I $opt:tt {
            filter($s:ident) {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            __I $opt { $($rest)* } [$($done)*] [
                $($filter)*
                [
                    st_name = $s,
                    body = {
                        $($body)*
                    },
                ]
            ]
        );
    };

    // &self bound method
    (
        __I $opt:tt {
            fn $fn_name:ident (&self as $s:ident $($params:tt)*) $(-> $t:ty)* {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            __I $opt { $($rest)* } [
                $($done)*
                [
                    st_name = $s,
                    bind_style = Ref,
                    body = { $($body)* },
                    result = result,
                    expanded = {
                        fn $fn_name(&self $($params)*) $(-> $t)* {
                            match *self { #result }
                        }
                    },
                ]
            ] [$($filter)*]
        );
    };

    // &mut self bound method
    (
        __I $opt:tt {
            fn $fn_name:ident (&mut self as $s:ident $($params:tt)*) $(-> $t:ty)* {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            __I $opt { $($rest)* } [
                $($done)*
                [
                    st_name = $s,
                    bind_style = RefMut,
                    body = { $($body)* },
                    result = result,
                    expanded = {
                        fn $fn_name(&mut self $($params)*) $(-> $t)* {
                            match *self { #result }
                        }
                    },
                ]
            ] [$($filter)*]
        );
    };

    // self bound method
    (
        __I $opt:tt {
            fn $fn_name:ident (self as $s:ident $($params:tt)*) $(-> $t:ty)* {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            __I $opt { $($rest)* } [
                $($done)*
                [
                    st_name = $s,
                    bind_style = Move,
                    body = { $($body)* },
                    result = result,
                    expanded = {
                        fn $fn_name(self $($params)*) $(-> $t)* {
                            match self { #result }
                        }
                    },
                ]
            ] [$($filter)*]
        );
    };

    // XXX: Static methods?

    // codegen after data collection
    (
        __I [$iname:ident, $path:path] {} [$(
            [
                st_name = $st_name:ident,
                bind_style = $bind_style:ident,
                body = $body:tt,
                result = $result:ident,
                expanded = { $($expanded:tt)* },
            ]
        )*] [$(
            [
                st_name = $filter_st_name:ident,
                body = $filter_body:tt,
            ]
        )*]
    ) => {
        fn $iname(mut st: $crate::Structure) -> $crate::macros::Tokens {
            let _ = &mut st; // Silence the unused mut warning

            // Filter/transform the `Structure` object before cloning it for
            // individual methods.
            $(
                {
                    let $filter_st_name = &mut st;
                    $filter_body
                }
            )*

            // Clone the `Structure` object and set the correct binding style,
            // then perform method specific expansion.
            $(
                let $result = {
                    let mut $st_name = st.clone();
                    $st_name.bind_with(|_| ::synstructure::BindStyle::$bind_style);
                    let $result = {
                        $body
                    };
                    quote!{ $($expanded)* }
                };
            )*

            st.bound_impl(quote!($path), quote!{
                $(#$result)*
            })
        }
    }
}
<|endoftext|>