<commit_before>use crate::chip::*;
use crate::database::*;
use crate::wires::*;
use crate::bels::*;

use std::collections::{BTreeSet, BTreeMap};
use std::fmt;

pub struct SitePin {
    pub tile_wire: String,
    pub site_wire: String,
    pub dir: PinDir,
}

impl fmt::Debug for SitePin {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} {} {}",
            &self.tile_wire,
            match self.dir {
                PinDir::INPUT => "-->",
                PinDir::OUTPUT => "<--",
                PinDir::INOUT => "<->",
            },
            &self.site_wire
        )
    }
}

pub struct SiteRoutingBel {
    pub src_wires: Vec<String>,
    pub dst_wire: String,
}

impl fmt::Debug for SiteRoutingBel {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} <-- {{", &self.dst_wire)?;
        let mut first = true;
        for src in self.src_wires.iter() {
            if !first { write!(f, ", ")?; }
            write!(f, "{}", src)?;
            first = false;
        }
        write!(f, "}}")?;
        Ok(())
    }
}

pub struct Site {
    pub name: String,
    pub pins: Vec<SitePin>,
    pub rbels: Vec<SiteRoutingBel>,
}

// To speed up site routing; where fixed connections connect multiple site wires together, merge them into one
// this structure stores the mapping in both directions
struct SiteWireMap {
    pub wire2root: BTreeMap<String, String>,
    pub root2wires: BTreeMap<String, BTreeSet<String>>,
}

impl SiteWireMap {
    pub fn lookup_wire(&self, name: &str) -> String {
        self.wire2root.get(name).unwrap_or(&name.to_string()).to_string()
    }
    pub fn add_alias(&mut self, root: &str, wire: &str) {
        self.wire2root.entry(wire.to_string()).or_insert(root.to_string());
        self.root2wires.entry(root.to_string()).or_insert(BTreeSet::new()).insert(wire.to_string());
        if let Some(wires) = self.root2wires.get(wire).cloned() {
            for w in wires {
                *self.wire2root.get_mut(&w).unwrap() = root.to_string();
                self.root2wires.get_mut(root).unwrap().insert(w.to_string());
            }
            self.root2wires.remove(wire);
        }
    }
}

// determine which wire has priority when flattening connections
fn compare_wire(a: &str, b: &str) -> bool {
    // prioritise shorter wires first, then fall back to a lexicographical compare
    (a.len(), a) < (b.len(), b)
}

fn flatten_wires(tile: &Tile, tiledata: &TileBitsDatabase) -> SiteWireMap {
    let mut m = SiteWireMap {
        wire2root: BTreeMap::new(),
        root2wires: BTreeMap::new(),
    };
    for (dst_wire, conns) in tiledata.conns.iter() {
        if !is_site_wire(tile, dst_wire) {
            continue;
        }
        for c in conns {
            let looked_up_src = m.lookup_wire(&c.from_wire);
            let looked_up_dst = m.lookup_wire(dst_wire);
            if compare_wire(&looked_up_src, &looked_up_dst) && is_site_wire(tile, &c.from_wire) {
                m.add_alias(&looked_up_src, &looked_up_dst);
            } else {
                m.add_alias(&looked_up_dst, &looked_up_src);
            }
        }
    }
    return m;
}

pub fn build_sites(_chip: &Chip, tile: &Tile, tiledata: &TileBitsDatabase) {
    let flat_wires = flatten_wires(tile, tiledata);
    let mut pins = Vec::new();
    let mut found_pins = BTreeSet::new();
    for (dst_wire, conns) in tiledata.conns.iter() {
        for conn in conns.iter() {
            if is_site_wire(tile, dst_wire) && !is_site_wire(tile, &conn.from_wire) {
                // from tile into site
                let site_dst_wire = flat_wires.lookup_wire(dst_wire);
                if found_pins.contains(&(conn.from_wire.to_string(), site_dst_wire.to_string())) {
                    continue;
                }
                found_pins.insert((conn.from_wire.to_string(), site_dst_wire.to_string()));
                pins.push(SitePin {
                    tile_wire: conn.from_wire.clone(),
                    site_wire: site_dst_wire,
                    dir: PinDir::INPUT,
                });
            } else if !is_site_wire(tile, dst_wire) && is_site_wire(tile, &conn.from_wire) {
                // from site into tile
                let site_src_wire = flat_wires.lookup_wire(&conn.from_wire);
                if found_pins.contains(&(site_src_wire.to_string(), dst_wire.to_string())) {
                    continue;
                }
                found_pins.insert((site_src_wire.to_string(), dst_wire.to_string()));
                pins.push(SitePin {
                    tile_wire: dst_wire.to_string(),
                    site_wire: site_src_wire,
                    dir: PinDir::OUTPUT,
                });
            }
        }
    }
    // For the F outputs where have a MUX/LUT choice; use the FF DI mux because it's not independently controllable from the FF mux
    for i in 0..4 {
            pins.push(SitePin {
                tile_wire: format!("F{}", 2*i),
                site_wire: flat_wires.lookup_wire(&format!("JDI0_SLICE{}", &"ABCD"[i..i+1])),
                dir: PinDir::OUTPUT,
            });
    }
    println!("Pins: ");
    for pin in pins.iter() {
        println!("    {:?}", pin);
    }
    let mut rbels = Vec::new();
    // Convert pips to routing bels
    for (dst_wire, pips) in tiledata.pips.iter() {
        if !is_site_wire(tile, dst_wire) {
            continue;
        }
        let site_dst_wire = flat_wires.lookup_wire(dst_wire);
        let mapped_src_wires = pips.iter().map(|p| &p.from_wire).filter(|w| is_site_wire(tile, w)).map(|w| flat_wires.lookup_wire(w)).collect();
        rbels.push(SiteRoutingBel {
            dst_wire: site_dst_wire,
            src_wires: mapped_src_wires,
        });
    }
    println!("Routing bels: ");
    for rbel in rbels.iter() {
        println!("    {:?}", rbel);
    }
}
<commit_msg>Import tile bels to site bels<commit_after>use crate::chip::*;
use crate::database::*;
use crate::wires::*;
use crate::bels::*;

use std::collections::{BTreeSet, BTreeMap};
use std::fmt;

pub struct SitePin {
    pub tile_wire: String,
    pub site_wire: String,
    pub dir: PinDir,
}

impl fmt::Debug for SitePin {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} {} {}",
            &self.tile_wire,
            match self.dir {
                PinDir::INPUT => "-->",
                PinDir::OUTPUT => "<--",
                PinDir::INOUT => "<->",
            },
            &self.site_wire
        )
    }
}

pub struct SiteRoutingBel {
    pub src_wires: Vec<String>,
    pub dst_wire: String,
}

impl fmt::Debug for SiteRoutingBel {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} <-- {{", &self.dst_wire)?;
        let mut first = true;
        for src in self.src_wires.iter() {
            if !first { write!(f, ", ")?; }
            write!(f, "{}", src)?;
            first = false;
        }
        write!(f, "}}")?;
        Ok(())
    }
}

pub struct SiteBelPin {
    pub pin_name: String,
    pub site_wire: String,
    pub dir: PinDir,
}

impl fmt::Debug for SiteBelPin {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} {} {}",
            &self.site_wire,
            match self.dir {
                PinDir::INPUT => "-->",
                PinDir::OUTPUT => "<--",
                PinDir::INOUT => "<->",
            },
            &self.pin_name
        )
    }
}

pub struct SiteFunctionalBel {
    pub name: String,
    pub bel_type: String,
    pub pins: Vec<SiteBelPin>,
}

pub struct Site {
    pub name: String,
    pub pins: Vec<SitePin>,
    pub rbels: Vec<SiteRoutingBel>,
}

// To speed up site routing; where fixed connections connect multiple site wires together, merge them into one
// this structure stores the mapping in both directions
struct SiteWireMap {
    pub wire2root: BTreeMap<String, String>,
    pub root2wires: BTreeMap<String, BTreeSet<String>>,
}

impl SiteWireMap {
    pub fn lookup_wire(&self, name: &str) -> String {
        self.wire2root.get(name).unwrap_or(&name.to_string()).to_string()
    }
    pub fn add_alias(&mut self, root: &str, wire: &str) {
        self.wire2root.entry(wire.to_string()).or_insert(root.to_string());
        self.root2wires.entry(root.to_string()).or_insert(BTreeSet::new()).insert(wire.to_string());
        if let Some(wires) = self.root2wires.get(wire).cloned() {
            for w in wires {
                *self.wire2root.get_mut(&w).unwrap() = root.to_string();
                self.root2wires.get_mut(root).unwrap().insert(w.to_string());
            }
            self.root2wires.remove(wire);
        }
    }
}

// determine which wire has priority when flattening connections
fn compare_wire(a: &str, b: &str) -> bool {
    // prioritise shorter wires first, then fall back to a lexicographical compare
    (a.len(), a) < (b.len(), b)
}

fn flatten_wires(tile: &Tile, tiledata: &TileBitsDatabase) -> SiteWireMap {
    let mut m = SiteWireMap {
        wire2root: BTreeMap::new(),
        root2wires: BTreeMap::new(),
    };
    for (dst_wire, conns) in tiledata.conns.iter() {
        if !is_site_wire(tile, dst_wire) {
            continue;
        }
        for c in conns {
            let looked_up_src = m.lookup_wire(&c.from_wire);
            let looked_up_dst = m.lookup_wire(dst_wire);
            if compare_wire(&looked_up_src, &looked_up_dst) && is_site_wire(tile, &c.from_wire) {
                m.add_alias(&looked_up_src, &looked_up_dst);
            } else {
                m.add_alias(&looked_up_dst, &looked_up_src);
            }
        }
    }
    return m;
}

pub fn build_sites(_chip: &Chip, tile: &Tile, tiledata: &TileBitsDatabase) {
    let flat_wires = flatten_wires(tile, tiledata);
    let mut pins = Vec::new();
    let mut found_pins = BTreeSet::new();
    for (dst_wire, conns) in tiledata.conns.iter() {
        for conn in conns.iter() {
            if is_site_wire(tile, dst_wire) && !is_site_wire(tile, &conn.from_wire) {
                // from tile into site
                let site_dst_wire = flat_wires.lookup_wire(dst_wire);
                if found_pins.contains(&(conn.from_wire.to_string(), site_dst_wire.to_string())) {
                    continue;
                }
                found_pins.insert((conn.from_wire.to_string(), site_dst_wire.to_string()));
                pins.push(SitePin {
                    tile_wire: conn.from_wire.clone(),
                    site_wire: site_dst_wire,
                    dir: PinDir::INPUT,
                });
            } else if !is_site_wire(tile, dst_wire) && is_site_wire(tile, &conn.from_wire) {
                // from site into tile
                let site_src_wire = flat_wires.lookup_wire(&conn.from_wire);
                if found_pins.contains(&(site_src_wire.to_string(), dst_wire.to_string())) {
                    continue;
                }
                found_pins.insert((site_src_wire.to_string(), dst_wire.to_string()));
                pins.push(SitePin {
                    tile_wire: dst_wire.to_string(),
                    site_wire: site_src_wire,
                    dir: PinDir::OUTPUT,
                });
            }
        }
    }
    // For the F outputs where have a MUX/LUT choice; use the FF DI mux because it's not independently controllable from the FF mux
    for i in 0..4 {
            pins.push(SitePin {
                tile_wire: format!("F{}", 2*i),
                site_wire: flat_wires.lookup_wire(&format!("JDI0_SLICE{}", &"ABCD"[i..i+1])),
                dir: PinDir::OUTPUT,
            });
    }
    println!("Pins: ");
    for pin in pins.iter() {
        println!("    {:?}", pin);
    }
    let mut rbels = Vec::new();
    // Convert pips to routing bels
    for (dst_wire, pips) in tiledata.pips.iter() {
        if !is_site_wire(tile, dst_wire) {
            continue;
        }
        let site_dst_wire = flat_wires.lookup_wire(dst_wire);
        let mapped_src_wires = pips.iter().map(|p| &p.from_wire).filter(|w| is_site_wire(tile, w)).map(|w| flat_wires.lookup_wire(w)).collect();
        rbels.push(SiteRoutingBel {
            dst_wire: site_dst_wire,
            src_wires: mapped_src_wires,
        });
    }
    println!();
    println!("Routing bels: ");
    for rbel in rbels.iter() {
        println!("    {:?}", rbel);
    }
    // Import functional bels
    let orig_bels = get_tile_bels(&tile.tiletype, tiledata);
    let mut site_bels = Vec::new();
    for orig_bel in orig_bels.iter() {
        let mut site_bel_pins = Vec::new();

        for pin in &orig_bel.pins {
            // TODO: relative X and Y coordinates
            let wire_name = pin.wire.rel_name(orig_bel.rel_x, orig_bel.rel_y);
            assert!(is_site_wire(tile, &wire_name));
            let site_wire = flat_wires.lookup_wire(&wire_name);
            site_bel_pins.push(SiteBelPin {
                pin_name: pin.name.clone(),
                site_wire: site_wire,
                dir: pin.dir.clone(),
            });
        }

        site_bels.push(SiteFunctionalBel {
            name: orig_bel.name.clone(),
            bel_type: orig_bel.beltype.clone(),
            pins: site_bel_pins,
        });
    }

    println!();
    println!("Functional bels: ");
    for fbel in site_bels.iter() {
        println!("    {}: {}", &fbel.name, &fbel.bel_type);
        for bp in fbel.pins.iter() {
            println!("        {:?}", bp);
        }
        println!();
    }
}
<|endoftext|>


<commit_before>// -*- flycheck-rust-crate-root: "lib.rs" -*-
use ffi = super::ffi;

use std::kinds::marker::ContravariantLifetime;

/// The object that will be used for node manipulations
pub struct XPathObject<'a> {
    wrapper: XPathObjectWrapper,
    lt: ContravariantLifetime<'a>
}

struct XPathObjectWrapper {
    xpath_object: *const ffi::XPathObject,
}

/// The nodeset
pub struct NodeSet<'a> {
    node_set: &'a ffi::NodeSet,
}

pub struct Node<'a> {
    node: &'a ffi::Node,
}

impl<'a> XPathObject<'a> {
    /// Gets a nodeset from the xpathobject
    pub fn get_node_set(&'a self) -> Option<NodeSet<'a>> {
        unsafe {
            let node_set_ptr = (*self.wrapper.xpath_object).node_set;
            if node_set_ptr.is_null() {
                None
            } else {
                Some(NodeSet { node_set: &*node_set_ptr })
            }
        }
    }
}

impl<'a> NodeSet<'a> {
    pub fn get_nodes(&'a self) -> Vec<Node<'a>> {
        unsafe {
            let node_ptr = self.node_set.node_tab;
            if node_ptr.is_null() {
                vec![]
            } else {
                range(0, self.node_set.node_nr).map(
                    |off| Node {
                        node: &*self.node_set.node_tab.clone().offset(off as int)
                    }).collect()
            }
        }
    }
}

pub fn from_raw_context<'a>(context: *const ffi::Context,
                        xpath: &str) -> Option<XPathObject<'a>> {
    let result =
        ffi::XPathObject::from_context(context, xpath);
    if result.is_null() {
        None
    } else {
        Some(XPathObject {
            wrapper: XPathObjectWrapper {
                xpath_object: result
            },
            lt: ContravariantLifetime
        })
    }
}

impl<'a> Drop for XPathObjectWrapper {
    fn drop(&mut self) {
        unsafe {
            ffi::xmlXPathFreeObject(self.xpath_object);
        }
    }
}
<commit_msg>Adding missing docs.<commit_after>// -*- flycheck-rust-crate-root: "lib.rs" -*-
use ffi = super::ffi;

use std::kinds::marker::ContravariantLifetime;

/// The object that will be used for node manipulations
pub struct XPathObject<'a> {
    wrapper: XPathObjectWrapper,
    lt: ContravariantLifetime<'a>
}

struct XPathObjectWrapper {
    xpath_object: *const ffi::XPathObject,
}

/// The nodeset
pub struct NodeSet<'a> {
    node_set: &'a ffi::NodeSet,
}

/// A node from the document
pub struct Node<'a> {
    node: &'a ffi::Node,
}

impl<'a> XPathObject<'a> {
    /// Gets a nodeset from the xpathobject
    pub fn get_node_set(&'a self) -> Option<NodeSet<'a>> {
        unsafe {
            let node_set_ptr = (*self.wrapper.xpath_object).node_set;
            if node_set_ptr.is_null() {
                None
            } else {
                Some(NodeSet { node_set: &*node_set_ptr })
            }
        }
    }
}

impl<'a> NodeSet<'a> {
    /// Gets a vector of nodes from the NodeSet
    pub fn get_nodes(&'a self) -> Vec<Node<'a>> {
        unsafe {
            let node_ptr = self.node_set.node_tab;
            if node_ptr.is_null() {
                vec![]
            } else {
                range(0, self.node_set.node_nr).map(
                    |off| Node {
                        node: &*self.node_set.node_tab.clone().offset(off as int)
                    }).collect()
            }
        }
    }
}

pub fn from_raw_context<'a>(context: *const ffi::Context,
                        xpath: &str) -> Option<XPathObject<'a>> {
    let result =
        ffi::XPathObject::from_context(context, xpath);
    if result.is_null() {
        None
    } else {
        Some(XPathObject {
            wrapper: XPathObjectWrapper {
                xpath_object: result
            },
            lt: ContravariantLifetime
        })
    }
}

impl<'a> Drop for XPathObjectWrapper {
    fn drop(&mut self) {
        unsafe {
            ffi::xmlXPathFreeObject(self.xpath_object);
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use analysis::{self, Loc};
use ir::{Function, BinaryOp, BitOp, IntOp, UnaryOp, Signedness, Size, Program, Reg, Block, Instruction, Value, BlockEnd, BlockId};

#[derive(Debug, Clone)]
enum Val {
    Ir(Value),
    Ref(Reg, u32),
    Unknown,
    Any,
}

impl Val {
    fn merge(self, other: Val) -> Val {
        match (self, other) {
            (Val::Any, other) | (other, Val::Any) => other,
            (Val::Unknown, _) | (_, Val::Unknown) => Val::Unknown,
            (Val::Ref(a, oa), Val::Ref(b, ob)) if (a, oa) == (b, ob) => Val::Ref(a, oa),
            (Val::Ir(a), Val::Ir(b)) => if a == b {
                Val::Ir(a)
            } else {
                Val::Unknown
            },
            _ => Val::Unknown,
        }
    }
}

struct Context<'a> {
    volatile: HashMap<Reg, HashSet<Loc>>,
    f: &'a Function,
    incoming: &'a HashMap<BlockId, Vec<BlockId>>,
    visited: HashSet<Loc>,
}

impl<'a> Context<'a> {
    fn is_volatile_at(&self, reg: Reg, loc: Loc) -> bool {
        if let Some(locs) = self.volatile.get(&reg) {
            locs.contains(&loc)
        } else {
            false
        }
    }

    fn dfs(&mut self, reg: Reg, block_id: BlockId, block: &Block, mut pos: usize) -> Val {
        loop {
            let loc = Loc { block: block_id, pos };
            if self.visited.contains(&loc) {
                return Val::Any;
            }
            self.visited.insert(loc);
            if pos == 0 {
                let mut total = Val::Any;
                if let Some(inc) = self.incoming.get(&block_id) {
                    for &parent in inc {
                        total = total.merge(self.dfs_block_end(reg, parent));
                    }
                }
                return total;
            } else {
                let loc = Loc { block: block_id, pos: pos - 1 };
                let op = &block.ops[pos - 1];
                match *op {
                    Instruction::Assign(r, ref val) |
                    Instruction::CastAssign(r, ref val) if r == reg => return Val::Ir(val.clone()),
                    Instruction::BinaryOp(r, _, _, _) |
                    Instruction::DerefLoad(r, _, _) |
                    Instruction::Load(r, _, _) |
                    Instruction::Store(r, _, _) if r == reg => return Val::Unknown,
                    Instruction::Call(r, _, _) |
                    Instruction::CallVirt(r, _, _) => {
                        if r == reg || self.is_volatile_at(reg, loc) {
                            return Val::Unknown;
                        }
                    }
                    Instruction::CallProc(_, _) |
                    Instruction::CallProcVirt(_, _) |
                    Instruction::DerefStore(_, _, _) => {
                        if self.is_volatile_at(reg, loc) {
                            return Val::Unknown;
                        }
                    }
                    Instruction::Drop(r) |
                    Instruction::Init(r) if r == reg => {
                        return Val::Any;
                    }
                    Instruction::TakeAddress(r, r2, offset) => {
                        if r == reg {
                            return Val::Ref(r2, offset);
                        }
                    }
                    _ => {}
                }
                pos -= 1;
            }
        }
    }

    fn dfs_block_end(&mut self, reg: Reg, block_id: BlockId) -> Val {
        let block = &self.f.blocks[&block_id];
        let pos = block.ops.len();
        self.dfs(reg, block_id, block, pos)
    }

    fn get_value(&mut self, reg: Reg, loc: Loc) -> Val {
        self.visited.clear();
        let block = &self.f.blocks[&loc.block];
        self.dfs(reg, loc.block, block, loc.pos)
    }
}

fn build_context<'a>(
    f: &'a Function,
    incoming: &'a mut HashMap<BlockId, Vec<BlockId>>,
) -> Context<'a> {
    incoming.clear();
    for (&id, block) in &f.blocks {
        match block.end {
            BlockEnd::Branch(_, a, b) => {
                incoming.entry(a).or_insert_with(Vec::new).push(id);
                incoming.entry(b).or_insert_with(Vec::new).push(id);
            }
            BlockEnd::Jump(a) => {
                incoming.entry(a).or_insert_with(Vec::new).push(id);
            }
            _ => {}
        }
    }
    Context {
        volatile: analysis::volatility::volatile_locations(f),
        f,
        incoming,
        visited: HashSet::new(),
    }
}

fn try_replace_val(val: &mut Value, ctx: &mut Context, loc: Loc) -> bool {
    if let Value::Reg(r) = *val {
        match ctx.get_value(r, loc) {
            Val::Any => {
                *val = Value::Undef;
                true
            }
            Val::Ir(v) => {
                *val = v;
                true
            }
            Val::Ref(_, _) |
            Val::Unknown => false
        }
    } else {
        false
    }
}

fn rewrite_function(f: &mut Function) {
    loop {
        let mut changed = false;
        let mut incoming = HashMap::new();
        let analyzed_f = f.clone();
        let ctx = &mut build_context(&analyzed_f, &mut incoming);
        for (&id, block) in &mut f.blocks {
            for (pos, op) in block.ops.iter_mut().enumerate() {
                let loc = Loc { block: id, pos };
                let mut replace_with = None;
                match *op {
                    Instruction::Assign(_, ref mut val) |
                    Instruction::CastAssign(_, ref mut val) => {
                        if try_replace_val(val, ctx, loc) {
                            changed = true;
                        }
                    }
                    Instruction::BinaryOp(r, op, ref mut a, ref mut b) => {
                        if let Some(result) = eval_binary_op(op, a, b) {
                            replace_with = Some(Instruction::Assign(r, result));
                        } else {
                            if try_replace_val(a, ctx, loc) {
                                changed = true;
                            }
                            if try_replace_val(b, ctx, loc) {
                                changed = true;
                            }
                        }
                    }
                    Instruction::Call(_, _, ref mut params) |
                    Instruction::CallProc(_, ref mut params) => {
                        for param in params {
                            if try_replace_val(param, ctx, loc) {
                                changed = true;
                            }
                        }
                    }
                    Instruction::CallVirt(_, ref mut f, ref mut params) |
                    Instruction::CallProcVirt(ref mut f, ref mut params) => {
                        if try_replace_val(f, ctx, loc) {
                            changed = true;
                        }
                        for param in params {
                            if try_replace_val(param, ctx, loc) {
                                changed = true;
                            }
                        }
                    }
                    Instruction::DerefLoad(r, Value::Reg(r2), 0) => {
                        match ctx.get_value(r2, loc) {
                            Val::Any => replace_with = Some(Instruction::Unreachable),
                            Val::Ir(v) => replace_with = Some(Instruction::DerefLoad(r, v, 0)),
                            Val::Ref(r3, 0) => replace_with = Some(Instruction::Assign(r, Value::Reg(r3))),
                            Val::Ref(_, _) |
                            Val::Unknown => {}
                        }
                    }
                    Instruction::DerefStore(ref to, offset, ref mut val) => {
                        if try_replace_val(val, ctx, loc) {
                            changed = true;
                        }
                        if let Value::Reg(r) = *to {
                            if offset == 0 {
                                match ctx.get_value(r, loc) {
                                    Val::Any => replace_with = Some(Instruction::Unreachable),
                                    Val::Ir(v) => replace_with = Some(Instruction::DerefStore(v, 0, val.clone())),
                                    Val::Ref(r, 0) => replace_with = Some(Instruction::Assign(r, val.clone())),
                                    Val::Ref(_, _) |
                                    Val::Unknown => {}
                                }
                            }
                        }
                    }
                    Instruction::DerefLoad(_, _, _) |
                    Instruction::Drop(_) |
                    Instruction::Init(_) |
                    Instruction::Nop |
                    Instruction::Load(_, _, _) |
                    Instruction::Store(_, _, _) |
                    Instruction::TakeAddress(_, _, _) |
                    Instruction::Unreachable => {}
                    Instruction::UnaryOp(r, op, ref mut val) => {
                        if let Some(result) = eval_unary_op(op, val) {
                            replace_with = Some(Instruction::Assign(r, result));
                        } else if try_replace_val(val, ctx, loc) {
                            changed = true;
                        }
                    }
                }
                if let Some(new_op) = replace_with {
                    *op = new_op;
                    changed = true;
                }
            }
            let loc = Loc { block: id, pos: block.ops.len() };
            match block.end {
                BlockEnd::Branch(ref mut val, _, _) |
                BlockEnd::Return(ref mut val) => {
                    if try_replace_val(val, ctx, loc) {
                        changed = true;
                    }
                }
                BlockEnd::Jump(_) | BlockEnd::ReturnProc => {}
            }
            if let BlockEnd::Branch(Value::Int(0, _), _, a) = block.end {
                block.end = BlockEnd::Jump(a);
                changed = true;
            } else if let BlockEnd::Branch(Value::Int(_, _), a, _) = block.end {
                block.end = BlockEnd::Jump(a);
                changed = true;
            }
        }
        if !changed {
            break;
        }
    }
}

fn eval_binary_op(op: BinaryOp, a: &Value, b: &Value) -> Option<Value> {
    let (a, b) = match (a, b) {
        (&Value::Int(a, _), &Value::Int(b, _)) => (a, b),
        _ => return None,
    };
    match op {
        BinaryOp::BitOp(BitOp::And, size) => {
            Some(Value::Int(a & b, size))
        }
        BinaryOp::BitOp(BitOp::Or, size) => {
            Some(Value::Int(a | b, size))
        }
        BinaryOp::BitOp(BitOp::Xor, size) => {
            Some(Value::Int(a ^ b, size))
        }
        BinaryOp::Eq => {
            let res = if a == b { 1 } else { 0 };
            Some(Value::Int(res, Size::Bit8))
        }
        BinaryOp::Neq => {
            let res = if a != b { 1 } else { 0 };
            Some(Value::Int(res, Size::Bit8))
        }
        BinaryOp::IntOp(IntOp::Add, _, size) => {
            let res = size.truncate(a.wrapping_add(b));
            Some(Value::Int(res, size))
        }
        BinaryOp::IntOp(IntOp::Sub, _, size) => {
            let res = size.truncate(a.wrapping_sub(b));
            Some(Value::Int(res, size))
        }
        BinaryOp::IntOp(IntOp::Mul, Signedness::Unsigned, size) => {
            let res = size.truncate(a.wrapping_mul(b));
            Some(Value::Int(res, size))
        }
        BinaryOp::IntOp(IntOp::Mul, Signedness::Signed, size) => {
            let a = size.to_signed(a);
            let b = size.to_signed(b);
            let res = size.truncate(a.wrapping_mul(b) as u64);
            Some(Value::Int(res, size))
        }
        BinaryOp::IntOp(IntOp::Div, Signedness::Unsigned, size) => {
            if b != 0 {
                let res = size.truncate(a.wrapping_div(b));
                Some(Value::Int(res, size))
            } else {
                // TODO: implement something like Value::Undef ?
                None
            }
        }
        BinaryOp::IntOp(IntOp::Div, Signedness::Signed, size) => {
            if b != 0 {
                let a = size.to_signed(a);
                let b = size.to_signed(b);
                let res = size.truncate(a.wrapping_div(b) as u64);
                Some(Value::Int(res, size))
            } else {
                // TODO: implement something like Value::Undef ?
                None
            }
        }
        BinaryOp::IntOp(IntOp::Mod, Signedness::Unsigned, size) => {
            if b != 0 {
                let res = size.truncate(a.wrapping_rem(b));
                Some(Value::Int(res, size))
            } else {
                // TODO: implement something like Value::Undef ?
                None
            }
        }
        BinaryOp::IntOp(IntOp::Mod, Signedness::Signed, size) => {
            if b != 0 {
                let a = size.to_signed(a);
                let b = size.to_signed(b);
                let res = size.truncate(a.wrapping_rem(b) as u64);
                Some(Value::Int(res, size))
            } else {
                // TODO: implement something like Value::Undef ?
                None
            }
        }
        BinaryOp::IntOp(IntOp::Greater, Signedness::Unsigned, size) => {
            Some(Value::Int(if a > b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::Greater, Signedness::Signed, size) => {
            let a = size.to_signed(a);
            let b = size.to_signed(b);
            Some(Value::Int(if a > b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::Less, Signedness::Unsigned, size) => {
            Some(Value::Int(if a < b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::Less, Signedness::Signed, size) => {
            let a = size.to_signed(a);
            let b = size.to_signed(b);
            Some(Value::Int(if a < b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::GreaterEq, Signedness::Unsigned, size) => {
            Some(Value::Int(if a >= b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::GreaterEq, Signedness::Signed, size) => {
            let a = size.to_signed(a);
            let b = size.to_signed(b);
            Some(Value::Int(if a >= b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::LessEq, Signedness::Unsigned, size) => {
            Some(Value::Int(if a > b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::LessEq, Signedness::Signed, size) => {
            let a = size.to_signed(a);
            let b = size.to_signed(b);
            Some(Value::Int(if a <= b { 1 } else { 0 }, size))
        }
    }
}

fn eval_unary_op(op: UnaryOp, a: &Value) -> Option<Value> {
    let a = match *a {
        Value::Int(a, _) => a,
        _ => return None,
    };
    match op {
        UnaryOp::Negate(_, size) => {
            let res = size.truncate((!a).wrapping_add(1));
            Some(Value::Int(res, size))
        }
    }
}

pub fn rewrite(program: &mut Program) {
    for f in program.functions.values_mut() {
        rewrite_function(f);
    }
}
<commit_msg>constant fold fix<commit_after>use std::collections::{HashMap, HashSet};
use analysis::{self, Loc};
use ir::{Function, BinaryOp, BitOp, IntOp, UnaryOp, Signedness, Size, Program, Reg, Block, Instruction, Value, BlockEnd, BlockId};

#[derive(Debug, Clone)]
enum Val {
    Ir(Value),
    Ref(Reg, u32),
    Unknown,
    Any,
}

impl Val {
    fn from_ir(v: &Value) -> Val {
        if let Value::Reg(_) = *v {
            Val::Unknown
        } else {
            Val::Ir(v.clone())
        }
    }

    fn merge(self, other: Val) -> Val {
        match (self, other) {
            (Val::Any, other) | (other, Val::Any) => other,
            (Val::Unknown, _) | (_, Val::Unknown) => Val::Unknown,
            (Val::Ref(a, oa), Val::Ref(b, ob)) if (a, oa) == (b, ob) => Val::Ref(a, oa),
            (Val::Ir(a), Val::Ir(b)) => if a == b {
                Val::Ir(a)
            } else {
                Val::Unknown
            },
            _ => Val::Unknown,
        }
    }
}

struct Context<'a> {
    volatile: HashMap<Reg, HashSet<Loc>>,
    f: &'a Function,
    incoming: &'a HashMap<BlockId, Vec<BlockId>>,
    visited: HashSet<Loc>,
}

impl<'a> Context<'a> {
    fn is_volatile_at(&self, reg: Reg, loc: Loc) -> bool {
        if let Some(locs) = self.volatile.get(&reg) {
            locs.contains(&loc)
        } else {
            false
        }
    }

    fn dfs(&mut self, reg: Reg, block_id: BlockId, block: &Block, mut pos: usize) -> Val {
        loop {
            let loc = Loc { block: block_id, pos };
            if self.visited.contains(&loc) {
                return Val::Any;
            }
            self.visited.insert(loc);
            if pos == 0 {
                let mut total = Val::Any;
                if let Some(inc) = self.incoming.get(&block_id) {
                    for &parent in inc {
                        total = total.merge(self.dfs_block_end(reg, parent));
                    }
                }
                return total;
            } else {
                let loc = Loc { block: block_id, pos: pos - 1 };
                let op = &block.ops[pos - 1];
                match *op {
                    Instruction::Assign(r, ref val) |
                    Instruction::CastAssign(r, ref val) if r == reg => return Val::from_ir(val),
                    Instruction::BinaryOp(r, _, _, _) |
                    Instruction::DerefLoad(r, _, _) |
                    Instruction::Load(r, _, _) |
                    Instruction::Store(r, _, _) if r == reg => return Val::Unknown,
                    Instruction::Call(r, _, _) |
                    Instruction::CallVirt(r, _, _) => {
                        if r == reg || self.is_volatile_at(reg, loc) {
                            return Val::Unknown;
                        }
                    }
                    Instruction::CallProc(_, _) |
                    Instruction::CallProcVirt(_, _) |
                    Instruction::DerefStore(_, _, _) => {
                        if self.is_volatile_at(reg, loc) {
                            return Val::Unknown;
                        }
                    }
                    Instruction::Drop(r) |
                    Instruction::Init(r) if r == reg => {
                        return Val::Any;
                    }
                    Instruction::TakeAddress(r, r2, offset) => {
                        if r == reg {
                            return Val::Ref(r2, offset);
                        }
                    }
                    _ => {}
                }
                pos -= 1;
            }
        }
    }

    fn dfs_block_end(&mut self, reg: Reg, block_id: BlockId) -> Val {
        let block = &self.f.blocks[&block_id];
        let pos = block.ops.len();
        self.dfs(reg, block_id, block, pos)
    }

    fn get_value(&mut self, reg: Reg, loc: Loc) -> Val {
        self.visited.clear();
        let block = &self.f.blocks[&loc.block];
        self.dfs(reg, loc.block, block, loc.pos)
    }
}

fn build_context<'a>(
    f: &'a Function,
    incoming: &'a mut HashMap<BlockId, Vec<BlockId>>,
) -> Context<'a> {
    incoming.clear();
    for (&id, block) in &f.blocks {
        match block.end {
            BlockEnd::Branch(_, a, b) => {
                incoming.entry(a).or_insert_with(Vec::new).push(id);
                incoming.entry(b).or_insert_with(Vec::new).push(id);
            }
            BlockEnd::Jump(a) => {
                incoming.entry(a).or_insert_with(Vec::new).push(id);
            }
            _ => {}
        }
    }
    Context {
        volatile: analysis::volatility::volatile_locations(f),
        f,
        incoming,
        visited: HashSet::new(),
    }
}

fn try_replace_val(val: &mut Value, ctx: &mut Context, loc: Loc) -> bool {
    if let Value::Reg(r) = *val {
        match ctx.get_value(r, loc) {
            Val::Any => {
                *val = Value::Undef;
                true
            }
            Val::Ir(v) => {
                *val = v;
                true
            }
            Val::Ref(_, _) |
            Val::Unknown => false
        }
    } else {
        false
    }
}

fn rewrite_function(f: &mut Function) {
    loop {
        let mut changed = false;
        let mut incoming = HashMap::new();
        let analyzed_f = f.clone();
        let ctx = &mut build_context(&analyzed_f, &mut incoming);
        for (&id, block) in &mut f.blocks {
            for (pos, op) in block.ops.iter_mut().enumerate() {
                let loc = Loc { block: id, pos };
                let mut replace_with = None;
                match *op {
                    Instruction::Assign(_, ref mut val) |
                    Instruction::CastAssign(_, ref mut val) => {
                        if try_replace_val(val, ctx, loc) {
                            changed = true;
                        }
                    }
                    Instruction::BinaryOp(r, op, ref mut a, ref mut b) => {
                        if let Some(result) = eval_binary_op(op, a, b) {
                            replace_with = Some(Instruction::Assign(r, result));
                        } else {
                            if try_replace_val(a, ctx, loc) {
                                changed = true;
                            }
                            if try_replace_val(b, ctx, loc) {
                                changed = true;
                            }
                        }
                    }
                    Instruction::Call(_, _, ref mut params) |
                    Instruction::CallProc(_, ref mut params) => {
                        for param in params {
                            if try_replace_val(param, ctx, loc) {
                                changed = true;
                            }
                        }
                    }
                    Instruction::CallVirt(_, ref mut f, ref mut params) |
                    Instruction::CallProcVirt(ref mut f, ref mut params) => {
                        if try_replace_val(f, ctx, loc) {
                            changed = true;
                        }
                        for param in params {
                            if try_replace_val(param, ctx, loc) {
                                changed = true;
                            }
                        }
                    }
                    Instruction::DerefLoad(r, Value::Reg(r2), 0) => {
                        match ctx.get_value(r2, loc) {
                            Val::Any => replace_with = Some(Instruction::Unreachable),
                            Val::Ir(v) => replace_with = Some(Instruction::DerefLoad(r, v, 0)),
                            Val::Ref(r3, 0) => replace_with = Some(Instruction::Assign(r, Value::Reg(r3))),
                            Val::Ref(_, _) |
                            Val::Unknown => {}
                        }
                    }
                    Instruction::DerefStore(ref to, offset, ref mut val) => {
                        if try_replace_val(val, ctx, loc) {
                            changed = true;
                        }
                        if let Value::Reg(r) = *to {
                            if offset == 0 {
                                match ctx.get_value(r, loc) {
                                    Val::Any => replace_with = Some(Instruction::Unreachable),
                                    Val::Ir(v) => replace_with = Some(Instruction::DerefStore(v, 0, val.clone())),
                                    Val::Ref(r, 0) => replace_with = Some(Instruction::Assign(r, val.clone())),
                                    Val::Ref(_, _) |
                                    Val::Unknown => {}
                                }
                            }
                        }
                    }
                    Instruction::DerefLoad(_, _, _) |
                    Instruction::Drop(_) |
                    Instruction::Init(_) |
                    Instruction::Nop |
                    Instruction::Load(_, _, _) |
                    Instruction::Store(_, _, _) |
                    Instruction::TakeAddress(_, _, _) |
                    Instruction::Unreachable => {}
                    Instruction::UnaryOp(r, op, ref mut val) => {
                        if let Some(result) = eval_unary_op(op, val) {
                            replace_with = Some(Instruction::Assign(r, result));
                        } else if try_replace_val(val, ctx, loc) {
                            changed = true;
                        }
                    }
                }
                if let Some(new_op) = replace_with {
                    *op = new_op;
                    changed = true;
                }
            }
            let loc = Loc { block: id, pos: block.ops.len() };
            match block.end {
                BlockEnd::Branch(ref mut val, _, _) |
                BlockEnd::Return(ref mut val) => {
                    if try_replace_val(val, ctx, loc) {
                        changed = true;
                    }
                }
                BlockEnd::Jump(_) | BlockEnd::ReturnProc => {}
            }
            if let BlockEnd::Branch(Value::Int(0, _), _, a) = block.end {
                block.end = BlockEnd::Jump(a);
                changed = true;
            } else if let BlockEnd::Branch(Value::Int(_, _), a, _) = block.end {
                block.end = BlockEnd::Jump(a);
                changed = true;
            }
        }
        if !changed {
            break;
        }
    }
}

fn eval_binary_op(op: BinaryOp, a: &Value, b: &Value) -> Option<Value> {
    let (a, b) = match (a, b) {
        (&Value::Int(a, _), &Value::Int(b, _)) => (a, b),
        _ => return None,
    };
    match op {
        BinaryOp::BitOp(BitOp::And, size) => {
            Some(Value::Int(a & b, size))
        }
        BinaryOp::BitOp(BitOp::Or, size) => {
            Some(Value::Int(a | b, size))
        }
        BinaryOp::BitOp(BitOp::Xor, size) => {
            Some(Value::Int(a ^ b, size))
        }
        BinaryOp::Eq => {
            let res = if a == b { 1 } else { 0 };
            Some(Value::Int(res, Size::Bit8))
        }
        BinaryOp::Neq => {
            let res = if a != b { 1 } else { 0 };
            Some(Value::Int(res, Size::Bit8))
        }
        BinaryOp::IntOp(IntOp::Add, _, size) => {
            let res = size.truncate(a.wrapping_add(b));
            Some(Value::Int(res, size))
        }
        BinaryOp::IntOp(IntOp::Sub, _, size) => {
            let res = size.truncate(a.wrapping_sub(b));
            Some(Value::Int(res, size))
        }
        BinaryOp::IntOp(IntOp::Mul, Signedness::Unsigned, size) => {
            let res = size.truncate(a.wrapping_mul(b));
            Some(Value::Int(res, size))
        }
        BinaryOp::IntOp(IntOp::Mul, Signedness::Signed, size) => {
            let a = size.to_signed(a);
            let b = size.to_signed(b);
            let res = size.truncate(a.wrapping_mul(b) as u64);
            Some(Value::Int(res, size))
        }
        BinaryOp::IntOp(IntOp::Div, Signedness::Unsigned, size) => {
            if b != 0 {
                let res = size.truncate(a.wrapping_div(b));
                Some(Value::Int(res, size))
            } else {
                // TODO: implement something like Value::Undef ?
                None
            }
        }
        BinaryOp::IntOp(IntOp::Div, Signedness::Signed, size) => {
            if b != 0 {
                let a = size.to_signed(a);
                let b = size.to_signed(b);
                let res = size.truncate(a.wrapping_div(b) as u64);
                Some(Value::Int(res, size))
            } else {
                // TODO: implement something like Value::Undef ?
                None
            }
        }
        BinaryOp::IntOp(IntOp::Mod, Signedness::Unsigned, size) => {
            if b != 0 {
                let res = size.truncate(a.wrapping_rem(b));
                Some(Value::Int(res, size))
            } else {
                // TODO: implement something like Value::Undef ?
                None
            }
        }
        BinaryOp::IntOp(IntOp::Mod, Signedness::Signed, size) => {
            if b != 0 {
                let a = size.to_signed(a);
                let b = size.to_signed(b);
                let res = size.truncate(a.wrapping_rem(b) as u64);
                Some(Value::Int(res, size))
            } else {
                // TODO: implement something like Value::Undef ?
                None
            }
        }
        BinaryOp::IntOp(IntOp::Greater, Signedness::Unsigned, size) => {
            Some(Value::Int(if a > b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::Greater, Signedness::Signed, size) => {
            let a = size.to_signed(a);
            let b = size.to_signed(b);
            Some(Value::Int(if a > b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::Less, Signedness::Unsigned, size) => {
            Some(Value::Int(if a < b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::Less, Signedness::Signed, size) => {
            let a = size.to_signed(a);
            let b = size.to_signed(b);
            Some(Value::Int(if a < b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::GreaterEq, Signedness::Unsigned, size) => {
            Some(Value::Int(if a >= b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::GreaterEq, Signedness::Signed, size) => {
            let a = size.to_signed(a);
            let b = size.to_signed(b);
            Some(Value::Int(if a >= b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::LessEq, Signedness::Unsigned, size) => {
            Some(Value::Int(if a > b { 1 } else { 0 }, size))
        }
        BinaryOp::IntOp(IntOp::LessEq, Signedness::Signed, size) => {
            let a = size.to_signed(a);
            let b = size.to_signed(b);
            Some(Value::Int(if a <= b { 1 } else { 0 }, size))
        }
    }
}

fn eval_unary_op(op: UnaryOp, a: &Value) -> Option<Value> {
    let a = match *a {
        Value::Int(a, _) => a,
        _ => return None,
    };
    match op {
        UnaryOp::Negate(_, size) => {
            let res = size.truncate((!a).wrapping_add(1));
            Some(Value::Int(res, size))
        }
    }
}

pub fn rewrite(program: &mut Program) {
    for f in program.functions.values_mut() {
        rewrite_function(f);
    }
}
<|endoftext|>


<commit_before>//! Request identity service for Actix applications.
//!
//! [**IdentityService**](struct.IdentityService.html) middleware can be
//! used with different policies types to store identity information.
//!
//! By default, only cookie identity policy is implemented. Other backend
//! implementations can be added separately.
//!
//! [**CookieIdentityPolicy**](struct.CookieIdentityPolicy.html)
//! uses cookies as identity storage.
//!
//! To access current request identity
//! [**Identity**](trait.Identity.html) extractor should be used.
//!
//! ```rust
//! use actix_web::middleware::identity::Identity;
//! use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService};
//! use actix_web::*;
//!
//! fn index(id: Identity) -> String {
//!     // access request identity
//!     if let Some(id) = id.identity() {
//!         format!("Welcome! {}", id)
//!     } else {
//!         "Welcome Anonymous!".to_owned()
//!     }
//! }
//!
//! fn login(id: Idenity) -> HttpResponse {
//!     id.remember("User1".to_owned()); // <- remember identity
//!     HttpResponse::Ok().finish()
//! }
//!
//! fn logout(id: Identity) -> HttpResponse {
//!     id.forget();                      // <- remove identity
//!     HttpResponse::Ok().finish()
//! }
//!
//! fn main() {
//!     let app = App::new().middleware(IdentityService::new(
//!         // <- create identity middleware
//!         CookieIdentityPolicy::new(&[0; 32])    // <- create cookie session backend
//!               .name("auth-cookie")
//!               .secure(false))
//!         .service(web::resource("/index.html").to(index)
//!         .service(web::resource("/login.html").to(login)
//!         .service(web::resource("/logout.html").to(logout)
//!     ));
//! }
//! ```
use std::cell::RefCell;
use std::rc::Rc;

use actix_service::{Service, Transform};
use cookie::{Cookie, CookieJar, Key, SameSite};
use futures::future::{ok, Either, FutureResult};
use futures::{Future, IntoFuture, Poll};
use time::Duration;

use crate::error::{Error, Result};
use crate::http::header::{self, HeaderValue};
use crate::request::HttpRequest;
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
use crate::FromRequest;
use crate::HttpMessage;

/// The extractor type to obtain your identity from a request.
///
/// ```rust
/// use actix_web::*;
/// use actix_web::middleware::identity::Identity;
///
/// fn index(id: Identity) -> Result<String> {
///     // access request identity
///     if let Some(id) = id.identity() {
///         Ok(format!("Welcome! {}", id))
///     } else {
///         Ok("Welcome Anonymous!".to_owned())
///     }
/// }
///
/// fn login(id: Identity) -> HttpResponse {
///     id.remember("User1".to_owned()); // <- remember identity
///     HttpResponse::Ok().finish()
/// }
///
/// fn logout(id: Identity) -> HttpResponse {
///     id.forget(); // <- remove identity
///     HttpResponse::Ok().finish()
/// }
/// # fn main() {}
/// ```
#[derive(Clone)]
pub struct Identity(HttpRequest);

impl Identity {
    /// Return the claimed identity of the user associated request or
    /// ``None`` if no identity can be found associated with the request.
    pub fn identity(&self) -> Option<String> {
        if let Some(id) = self.0.extensions().get::<IdentityItem>() {
            id.id.clone()
        } else {
            None
        }
    }

    /// Remember identity.
    pub fn remember(&self, identity: String) {
        if let Some(id) = self.0.extensions_mut().get_mut::<IdentityItem>() {
            id.id = Some(identity);
            id.changed = true;
        }
    }

    /// This method is used to 'forget' the current identity on subsequent
    /// requests.
    pub fn forget(&self) {
        if let Some(id) = self.0.extensions_mut().get_mut::<IdentityItem>() {
            id.id = None;
            id.changed = true;
        }
    }
}

struct IdentityItem {
    id: Option<String>,
    changed: bool,
}

/// Extractor implementation for Identity type.
///
/// ```rust
/// # use actix_web::*;
/// use actix_web::middleware::identity::Identity;
///
/// fn index(id: Identity) -> String {
///     // access request identity
///     if let Some(id) = id.identity() {
///         format!("Welcome! {}", id)
///     } else {
///         "Welcome Anonymous!".to_owned()
///     }
/// }
/// # fn main() {}
/// ```
impl<P> FromRequest<P> for Identity {
    type Error = Error;
    type Future = Result<Identity, Error>;
    type Config = ();

    #[inline]
    fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
        Ok(Identity(req.clone()))
    }
}

/// Identity policy definition.
pub trait IdentityPolicy: Sized + 'static {
    /// The return type of the middleware
    type Future: IntoFuture<Item = Option<String>, Error = Error>;

    /// The return type of the middleware
    type ResponseFuture: IntoFuture<Item = (), Error = Error>;

    /// Parse the session from request and load data from a service identity.
    fn from_request<P>(&self, request: &mut ServiceRequest<P>) -> Self::Future;

    /// Write changes to response
    fn to_response<B>(
        &self,
        identity: Option<String>,
        changed: bool,
        response: &mut ServiceResponse<B>,
    ) -> Self::ResponseFuture;
}

/// Request identity middleware
///
/// ```rust
/// use actix_web::App;
/// use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService};
///
/// fn main() {
///     let app = App::new().middleware(IdentityService::new(
///         // <- create identity middleware
///         CookieIdentityPolicy::new(&[0; 32])    // <- create cookie session backend
///               .name("auth-cookie")
///               .secure(false),
///     ));
/// }
/// ```
pub struct IdentityService<T> {
    backend: Rc<T>,
}

impl<T> IdentityService<T> {
    /// Create new identity service with specified backend.
    pub fn new(backend: T) -> Self {
        IdentityService {
            backend: Rc::new(backend),
        }
    }
}

impl<S, T, P, B> Transform<S> for IdentityService<T>
where
    P: 'static,
    S: Service<Request = ServiceRequest<P>, Response = ServiceResponse<B>> + 'static,
    S::Future: 'static,
    T: IdentityPolicy,
    B: 'static,
{
    type Request = ServiceRequest<P>;
    type Response = ServiceResponse<B>;
    type Error = S::Error;
    type InitError = ();
    type Transform = IdentityServiceMiddleware<S, T>;
    type Future = FutureResult<Self::Transform, Self::InitError>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(IdentityServiceMiddleware {
            backend: self.backend.clone(),
            service: Rc::new(RefCell::new(service)),
        })
    }
}

#[doc(hidden)]
pub struct IdentityServiceMiddleware<S, T> {
    backend: Rc<T>,
    service: Rc<RefCell<S>>,
}

impl<S, T, P, B> Service for IdentityServiceMiddleware<S, T>
where
    P: 'static,
    B: 'static,
    S: Service<Request = ServiceRequest<P>, Response = ServiceResponse<B>> + 'static,
    S::Future: 'static,
    T: IdentityPolicy,
{
    type Request = ServiceRequest<P>;
    type Response = ServiceResponse<B>;
    type Error = S::Error;
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        self.service.borrow_mut().poll_ready()
    }

    fn call(&mut self, mut req: ServiceRequest<P>) -> Self::Future {
        let srv = self.service.clone();
        let backend = self.backend.clone();

        Box::new(
            self.backend.from_request(&mut req).into_future().then(
                move |res| match res {
                    Ok(id) => {
                        req.extensions_mut()
                            .insert(IdentityItem { id, changed: false });

                        Either::A(srv.borrow_mut().call(req).and_then(move |mut res| {
                            let id =
                                res.request().extensions_mut().remove::<IdentityItem>();

                            if let Some(id) = id {
                                return Either::A(
                                    backend
                                        .to_response(id.id, id.changed, &mut res)
                                        .into_future()
                                        .then(move |t| match t {
                                            Ok(_) => Ok(res),
                                            Err(e) => Ok(res.error_response(e)),
                                        }),
                                );
                            } else {
                                Either::B(ok(res))
                            }
                        }))
                    }
                    Err(err) => Either::B(ok(req.error_response(err))),
                },
            ),
        )
    }
}

struct CookieIdentityInner {
    key: Key,
    name: String,
    path: String,
    domain: Option<String>,
    secure: bool,
    max_age: Option<Duration>,
    same_site: Option<SameSite>,
}

impl CookieIdentityInner {
    fn new(key: &[u8]) -> CookieIdentityInner {
        CookieIdentityInner {
            key: Key::from_master(key),
            name: "actix-identity".to_owned(),
            path: "/".to_owned(),
            domain: None,
            secure: true,
            max_age: None,
            same_site: None,
        }
    }

    fn set_cookie<B>(
        &self,
        resp: &mut ServiceResponse<B>,
        id: Option<String>,
    ) -> Result<()> {
        let some = id.is_some();
        {
            let id = id.unwrap_or_else(String::new);
            let mut cookie = Cookie::new(self.name.clone(), id);
            cookie.set_path(self.path.clone());
            cookie.set_secure(self.secure);
            cookie.set_http_only(true);

            if let Some(ref domain) = self.domain {
                cookie.set_domain(domain.clone());
            }

            if let Some(max_age) = self.max_age {
                cookie.set_max_age(max_age);
            }

            if let Some(same_site) = self.same_site {
                cookie.set_same_site(same_site);
            }

            let mut jar = CookieJar::new();
            if some {
                jar.private(&self.key).add(cookie);
            } else {
                jar.add_original(cookie.clone());
                jar.private(&self.key).remove(cookie);
            }

            for cookie in jar.delta() {
                let val = HeaderValue::from_str(&cookie.to_string())?;
                resp.headers_mut().append(header::SET_COOKIE, val);
            }
        }

        Ok(())
    }

    fn load<T>(&self, req: &ServiceRequest<T>) -> Option<String> {
        if let Ok(cookies) = req.cookies() {
            for cookie in cookies.iter() {
                if cookie.name() == self.name {
                    let mut jar = CookieJar::new();
                    jar.add_original(cookie.clone());

                    let cookie_opt = jar.private(&self.key).get(&self.name);
                    if let Some(cookie) = cookie_opt {
                        return Some(cookie.value().into());
                    }
                }
            }
        }
        None
    }
}

/// Use cookies for request identity storage.
///
/// The constructors take a key as an argument.
/// This is the private key for cookie - when this value is changed,
/// all identities are lost. The constructors will panic if the key is less
/// than 32 bytes in length.
///
/// # Example
///
/// ```rust
/// # extern crate actix_web;
/// use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService};
/// use actix_web::App;
///
/// fn main() {
///     let app = App::new().middleware(IdentityService::new(
///         // <- create identity middleware
///         CookieIdentityPolicy::new(&[0; 32])  // <- construct cookie policy
///                .domain("www.rust-lang.org")
///                .name("actix_auth")
///                .path("/")
///                .secure(true),
///     ));
/// }
/// ```
pub struct CookieIdentityPolicy(Rc<CookieIdentityInner>);

impl CookieIdentityPolicy {
    /// Construct new `CookieIdentityPolicy` instance.
    ///
    /// Panics if key length is less than 32 bytes.
    pub fn new(key: &[u8]) -> CookieIdentityPolicy {
        CookieIdentityPolicy(Rc::new(CookieIdentityInner::new(key)))
    }

    /// Sets the `path` field in the session cookie being built.
    pub fn path<S: Into<String>>(mut self, value: S) -> CookieIdentityPolicy {
        Rc::get_mut(&mut self.0).unwrap().path = value.into();
        self
    }

    /// Sets the `name` field in the session cookie being built.
    pub fn name<S: Into<String>>(mut self, value: S) -> CookieIdentityPolicy {
        Rc::get_mut(&mut self.0).unwrap().name = value.into();
        self
    }

    /// Sets the `domain` field in the session cookie being built.
    pub fn domain<S: Into<String>>(mut self, value: S) -> CookieIdentityPolicy {
        Rc::get_mut(&mut self.0).unwrap().domain = Some(value.into());
        self
    }

    /// Sets the `secure` field in the session cookie being built.
    ///
    /// If the `secure` field is set, a cookie will only be transmitted when the
    /// connection is secure - i.e. `https`
    pub fn secure(mut self, value: bool) -> CookieIdentityPolicy {
        Rc::get_mut(&mut self.0).unwrap().secure = value;
        self
    }

    /// Sets the `max-age` field in the session cookie being built.
    pub fn max_age(mut self, value: Duration) -> CookieIdentityPolicy {
        Rc::get_mut(&mut self.0).unwrap().max_age = Some(value);
        self
    }

    /// Sets the `same_site` field in the session cookie being built.
    pub fn same_site(mut self, same_site: SameSite) -> Self {
        Rc::get_mut(&mut self.0).unwrap().same_site = Some(same_site);
        self
    }
}

impl IdentityPolicy for CookieIdentityPolicy {
    type Future = Result<Option<String>, Error>;
    type ResponseFuture = Result<(), Error>;

    fn from_request<P>(&self, req: &mut ServiceRequest<P>) -> Self::Future {
        Ok(self.0.load(req))
    }

    fn to_response<B>(
        &self,
        id: Option<String>,
        changed: bool,
        res: &mut ServiceResponse<B>,
    ) -> Self::ResponseFuture {
        if changed {
            let _ = self.0.set_cookie(res, id);
        }
        Ok(())
    }
}
<commit_msg>fix doc tests<commit_after>//! Request identity service for Actix applications.
//!
//! [**IdentityService**](struct.IdentityService.html) middleware can be
//! used with different policies types to store identity information.
//!
//! By default, only cookie identity policy is implemented. Other backend
//! implementations can be added separately.
//!
//! [**CookieIdentityPolicy**](struct.CookieIdentityPolicy.html)
//! uses cookies as identity storage.
//!
//! To access current request identity
//! [**Identity**](trait.Identity.html) extractor should be used.
//!
//! ```rust
//! use actix_web::middleware::identity::Identity;
//! use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService};
//! use actix_web::*;
//!
//! fn index(id: Identity) -> String {
//!     // access request identity
//!     if let Some(id) = id.identity() {
//!         format!("Welcome! {}", id)
//!     } else {
//!         "Welcome Anonymous!".to_owned()
//!     }
//! }
//!
//! fn login(id: Identity) -> HttpResponse {
//!     id.remember("User1".to_owned()); // <- remember identity
//!     HttpResponse::Ok().finish()
//! }
//!
//! fn logout(id: Identity) -> HttpResponse {
//!     id.forget();                      // <- remove identity
//!     HttpResponse::Ok().finish()
//! }
//!
//! fn main() {
//!     let app = App::new().middleware(IdentityService::new(
//!         // <- create identity middleware
//!         CookieIdentityPolicy::new(&[0; 32])    // <- create cookie session backend
//!               .name("auth-cookie")
//!               .secure(false)))
//!         .service(web::resource("/index.html").to(index))
//!         .service(web::resource("/login.html").to(login))
//!         .service(web::resource("/logout.html").to(logout));
//! }
//! ```
use std::cell::RefCell;
use std::rc::Rc;

use actix_service::{Service, Transform};
use cookie::{Cookie, CookieJar, Key, SameSite};
use futures::future::{ok, Either, FutureResult};
use futures::{Future, IntoFuture, Poll};
use time::Duration;

use crate::error::{Error, Result};
use crate::http::header::{self, HeaderValue};
use crate::request::HttpRequest;
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
use crate::FromRequest;
use crate::HttpMessage;

/// The extractor type to obtain your identity from a request.
///
/// ```rust
/// use actix_web::*;
/// use actix_web::middleware::identity::Identity;
///
/// fn index(id: Identity) -> Result<String> {
///     // access request identity
///     if let Some(id) = id.identity() {
///         Ok(format!("Welcome! {}", id))
///     } else {
///         Ok("Welcome Anonymous!".to_owned())
///     }
/// }
///
/// fn login(id: Identity) -> HttpResponse {
///     id.remember("User1".to_owned()); // <- remember identity
///     HttpResponse::Ok().finish()
/// }
///
/// fn logout(id: Identity) -> HttpResponse {
///     id.forget(); // <- remove identity
///     HttpResponse::Ok().finish()
/// }
/// # fn main() {}
/// ```
#[derive(Clone)]
pub struct Identity(HttpRequest);

impl Identity {
    /// Return the claimed identity of the user associated request or
    /// ``None`` if no identity can be found associated with the request.
    pub fn identity(&self) -> Option<String> {
        if let Some(id) = self.0.extensions().get::<IdentityItem>() {
            id.id.clone()
        } else {
            None
        }
    }

    /// Remember identity.
    pub fn remember(&self, identity: String) {
        if let Some(id) = self.0.extensions_mut().get_mut::<IdentityItem>() {
            id.id = Some(identity);
            id.changed = true;
        }
    }

    /// This method is used to 'forget' the current identity on subsequent
    /// requests.
    pub fn forget(&self) {
        if let Some(id) = self.0.extensions_mut().get_mut::<IdentityItem>() {
            id.id = None;
            id.changed = true;
        }
    }
}

struct IdentityItem {
    id: Option<String>,
    changed: bool,
}

/// Extractor implementation for Identity type.
///
/// ```rust
/// # use actix_web::*;
/// use actix_web::middleware::identity::Identity;
///
/// fn index(id: Identity) -> String {
///     // access request identity
///     if let Some(id) = id.identity() {
///         format!("Welcome! {}", id)
///     } else {
///         "Welcome Anonymous!".to_owned()
///     }
/// }
/// # fn main() {}
/// ```
impl<P> FromRequest<P> for Identity {
    type Error = Error;
    type Future = Result<Identity, Error>;
    type Config = ();

    #[inline]
    fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
        Ok(Identity(req.clone()))
    }
}

/// Identity policy definition.
pub trait IdentityPolicy: Sized + 'static {
    /// The return type of the middleware
    type Future: IntoFuture<Item = Option<String>, Error = Error>;

    /// The return type of the middleware
    type ResponseFuture: IntoFuture<Item = (), Error = Error>;

    /// Parse the session from request and load data from a service identity.
    fn from_request<P>(&self, request: &mut ServiceRequest<P>) -> Self::Future;

    /// Write changes to response
    fn to_response<B>(
        &self,
        identity: Option<String>,
        changed: bool,
        response: &mut ServiceResponse<B>,
    ) -> Self::ResponseFuture;
}

/// Request identity middleware
///
/// ```rust
/// use actix_web::App;
/// use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService};
///
/// fn main() {
///     let app = App::new().middleware(IdentityService::new(
///         // <- create identity middleware
///         CookieIdentityPolicy::new(&[0; 32])    // <- create cookie session backend
///               .name("auth-cookie")
///               .secure(false),
///     ));
/// }
/// ```
pub struct IdentityService<T> {
    backend: Rc<T>,
}

impl<T> IdentityService<T> {
    /// Create new identity service with specified backend.
    pub fn new(backend: T) -> Self {
        IdentityService {
            backend: Rc::new(backend),
        }
    }
}

impl<S, T, P, B> Transform<S> for IdentityService<T>
where
    P: 'static,
    S: Service<Request = ServiceRequest<P>, Response = ServiceResponse<B>> + 'static,
    S::Future: 'static,
    T: IdentityPolicy,
    B: 'static,
{
    type Request = ServiceRequest<P>;
    type Response = ServiceResponse<B>;
    type Error = S::Error;
    type InitError = ();
    type Transform = IdentityServiceMiddleware<S, T>;
    type Future = FutureResult<Self::Transform, Self::InitError>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(IdentityServiceMiddleware {
            backend: self.backend.clone(),
            service: Rc::new(RefCell::new(service)),
        })
    }
}

#[doc(hidden)]
pub struct IdentityServiceMiddleware<S, T> {
    backend: Rc<T>,
    service: Rc<RefCell<S>>,
}

impl<S, T, P, B> Service for IdentityServiceMiddleware<S, T>
where
    P: 'static,
    B: 'static,
    S: Service<Request = ServiceRequest<P>, Response = ServiceResponse<B>> + 'static,
    S::Future: 'static,
    T: IdentityPolicy,
{
    type Request = ServiceRequest<P>;
    type Response = ServiceResponse<B>;
    type Error = S::Error;
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        self.service.borrow_mut().poll_ready()
    }

    fn call(&mut self, mut req: ServiceRequest<P>) -> Self::Future {
        let srv = self.service.clone();
        let backend = self.backend.clone();

        Box::new(
            self.backend.from_request(&mut req).into_future().then(
                move |res| match res {
                    Ok(id) => {
                        req.extensions_mut()
                            .insert(IdentityItem { id, changed: false });

                        Either::A(srv.borrow_mut().call(req).and_then(move |mut res| {
                            let id =
                                res.request().extensions_mut().remove::<IdentityItem>();

                            if let Some(id) = id {
                                return Either::A(
                                    backend
                                        .to_response(id.id, id.changed, &mut res)
                                        .into_future()
                                        .then(move |t| match t {
                                            Ok(_) => Ok(res),
                                            Err(e) => Ok(res.error_response(e)),
                                        }),
                                );
                            } else {
                                Either::B(ok(res))
                            }
                        }))
                    }
                    Err(err) => Either::B(ok(req.error_response(err))),
                },
            ),
        )
    }
}

struct CookieIdentityInner {
    key: Key,
    name: String,
    path: String,
    domain: Option<String>,
    secure: bool,
    max_age: Option<Duration>,
    same_site: Option<SameSite>,
}

impl CookieIdentityInner {
    fn new(key: &[u8]) -> CookieIdentityInner {
        CookieIdentityInner {
            key: Key::from_master(key),
            name: "actix-identity".to_owned(),
            path: "/".to_owned(),
            domain: None,
            secure: true,
            max_age: None,
            same_site: None,
        }
    }

    fn set_cookie<B>(
        &self,
        resp: &mut ServiceResponse<B>,
        id: Option<String>,
    ) -> Result<()> {
        let some = id.is_some();
        {
            let id = id.unwrap_or_else(String::new);
            let mut cookie = Cookie::new(self.name.clone(), id);
            cookie.set_path(self.path.clone());
            cookie.set_secure(self.secure);
            cookie.set_http_only(true);

            if let Some(ref domain) = self.domain {
                cookie.set_domain(domain.clone());
            }

            if let Some(max_age) = self.max_age {
                cookie.set_max_age(max_age);
            }

            if let Some(same_site) = self.same_site {
                cookie.set_same_site(same_site);
            }

            let mut jar = CookieJar::new();
            if some {
                jar.private(&self.key).add(cookie);
            } else {
                jar.add_original(cookie.clone());
                jar.private(&self.key).remove(cookie);
            }

            for cookie in jar.delta() {
                let val = HeaderValue::from_str(&cookie.to_string())?;
                resp.headers_mut().append(header::SET_COOKIE, val);
            }
        }

        Ok(())
    }

    fn load<T>(&self, req: &ServiceRequest<T>) -> Option<String> {
        if let Ok(cookies) = req.cookies() {
            for cookie in cookies.iter() {
                if cookie.name() == self.name {
                    let mut jar = CookieJar::new();
                    jar.add_original(cookie.clone());

                    let cookie_opt = jar.private(&self.key).get(&self.name);
                    if let Some(cookie) = cookie_opt {
                        return Some(cookie.value().into());
                    }
                }
            }
        }
        None
    }
}

/// Use cookies for request identity storage.
///
/// The constructors take a key as an argument.
/// This is the private key for cookie - when this value is changed,
/// all identities are lost. The constructors will panic if the key is less
/// than 32 bytes in length.
///
/// # Example
///
/// ```rust
/// # extern crate actix_web;
/// use actix_web::middleware::identity::{CookieIdentityPolicy, IdentityService};
/// use actix_web::App;
///
/// fn main() {
///     let app = App::new().middleware(IdentityService::new(
///         // <- create identity middleware
///         CookieIdentityPolicy::new(&[0; 32])  // <- construct cookie policy
///                .domain("www.rust-lang.org")
///                .name("actix_auth")
///                .path("/")
///                .secure(true),
///     ));
/// }
/// ```
pub struct CookieIdentityPolicy(Rc<CookieIdentityInner>);

impl CookieIdentityPolicy {
    /// Construct new `CookieIdentityPolicy` instance.
    ///
    /// Panics if key length is less than 32 bytes.
    pub fn new(key: &[u8]) -> CookieIdentityPolicy {
        CookieIdentityPolicy(Rc::new(CookieIdentityInner::new(key)))
    }

    /// Sets the `path` field in the session cookie being built.
    pub fn path<S: Into<String>>(mut self, value: S) -> CookieIdentityPolicy {
        Rc::get_mut(&mut self.0).unwrap().path = value.into();
        self
    }

    /// Sets the `name` field in the session cookie being built.
    pub fn name<S: Into<String>>(mut self, value: S) -> CookieIdentityPolicy {
        Rc::get_mut(&mut self.0).unwrap().name = value.into();
        self
    }

    /// Sets the `domain` field in the session cookie being built.
    pub fn domain<S: Into<String>>(mut self, value: S) -> CookieIdentityPolicy {
        Rc::get_mut(&mut self.0).unwrap().domain = Some(value.into());
        self
    }

    /// Sets the `secure` field in the session cookie being built.
    ///
    /// If the `secure` field is set, a cookie will only be transmitted when the
    /// connection is secure - i.e. `https`
    pub fn secure(mut self, value: bool) -> CookieIdentityPolicy {
        Rc::get_mut(&mut self.0).unwrap().secure = value;
        self
    }

    /// Sets the `max-age` field in the session cookie being built.
    pub fn max_age(mut self, value: Duration) -> CookieIdentityPolicy {
        Rc::get_mut(&mut self.0).unwrap().max_age = Some(value);
        self
    }

    /// Sets the `same_site` field in the session cookie being built.
    pub fn same_site(mut self, same_site: SameSite) -> Self {
        Rc::get_mut(&mut self.0).unwrap().same_site = Some(same_site);
        self
    }
}

impl IdentityPolicy for CookieIdentityPolicy {
    type Future = Result<Option<String>, Error>;
    type ResponseFuture = Result<(), Error>;

    fn from_request<P>(&self, req: &mut ServiceRequest<P>) -> Self::Future {
        Ok(self.0.load(req))
    }

    fn to_response<B>(
        &self,
        id: Option<String>,
        changed: bool,
        res: &mut ServiceResponse<B>,
    ) -> Self::ResponseFuture {
        if changed {
            let _ = self.0.set_cookie(res, id);
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 use dom::bindings::codegen::Bindings::TestBindingProxyBinding::TestBindingProxyMethods;
 use dom::bindings::utils::Reflector;
 use util::str::DOMString;

 #[dom_struct]
 pub struct TestBindingProxy {
     reflector_: Reflector
 }

 impl<'a> TestBindingProxyMethods for &'a TestBindingProxy {

     fn GetNamedItem(self, _: DOMString) -> DOMString {"".to_owned()}
     fn SetNamedItem(self, _: DOMString, _: DOMString) -> () {}
     fn GetItem(self, _: u32) -> DOMString {"".to_owned()}
     fn SetItem(self, _: u32, _: DOMString) -> () {}
     fn RemoveItem(self, _: DOMString) -> () {}
     fn Stringifier(self) -> DOMString {"".to_owned()}
     fn NamedCreator(self, _: DOMString, _: DOMString) -> () {}
     fn IndexedGetter(self, _: u32, _: &mut bool) -> DOMString {"".to_owned()}
     fn NamedDeleter(self, _: DOMString) -> () {}
     fn IndexedSetter(self, _: u32, _: DOMString) -> () {}
     fn NamedSetter(self, _: DOMString, _: DOMString) -> () {}
     fn IndexedCreator(self, _: u32, _: DOMString) -> () {}
     fn NamedGetter(self, _: DOMString, _: &mut bool) -> DOMString {"".to_owned()}

 }
<commit_msg>Fix indentation in testbindingproxy.rs<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::Bindings::TestBindingProxyBinding::TestBindingProxyMethods;
use dom::bindings::utils::Reflector;
use util::str::DOMString;

#[dom_struct]
pub struct TestBindingProxy {
    reflector_: Reflector
}

impl<'a> TestBindingProxyMethods for &'a TestBindingProxy {

    fn GetNamedItem(self, _: DOMString) -> DOMString {"".to_owned()}
    fn SetNamedItem(self, _: DOMString, _: DOMString) -> () {}
    fn GetItem(self, _: u32) -> DOMString {"".to_owned()}
    fn SetItem(self, _: u32, _: DOMString) -> () {}
    fn RemoveItem(self, _: DOMString) -> () {}
    fn Stringifier(self) -> DOMString {"".to_owned()}
    fn NamedCreator(self, _: DOMString, _: DOMString) -> () {}
    fn IndexedGetter(self, _: u32, _: &mut bool) -> DOMString {"".to_owned()}
    fn NamedDeleter(self, _: DOMString) -> () {}
    fn IndexedSetter(self, _: u32, _: DOMString) -> () {}
    fn NamedSetter(self, _: DOMString, _: DOMString) -> () {}
    fn IndexedCreator(self, _: u32, _: DOMString) -> () {}
    fn NamedGetter(self, _: DOMString, _: &mut bool) -> DOMString {"".to_owned()}

}
<|endoftext|>


<commit_before>use combine::*;
use combine::char::char;
use combine::primitives::RangeStream;
use parser::errors::CustomError;
use parser::trivia::ws;
use parser::key::key;
use parser::value::value;
use value::{InlineTable, KeyValue};
use decor::{InternalString, Repr};
use formatted::decorated;

// ;; Inline Table

// inline-table = inline-table-open inline-table-keyvals inline-table-close
parse!(inline_table() -> InlineTable, {
    between(char(INLINE_TABLE_OPEN), char(INLINE_TABLE_CLOSE),
            inline_table_keyvals().and_then(|(p, v)| table_from_pairs(p, v)))
});

fn table_from_pairs(
    preamble: &str,
    v: Vec<(InternalString, KeyValue)>,
) -> Result<InlineTable, CustomError> {
    let mut table = InlineTable::default();
    table.preamble = InternalString::from(preamble);

    for (k, kv) in v {
        if table.contains_key(&k) {
            return Err(CustomError::DuplicateKey {
                key: k.into(),
                table: "inline".into(),
            });
        }
        table.key_value_pairs.insert(k, kv);
    }
    Ok(table)
}

// inline-table-open  = %x7B ws     ; {
const INLINE_TABLE_OPEN: char = '{';
// inline-table-close = ws %x7D     ; }
const INLINE_TABLE_CLOSE: char = '}';
// inline-table-sep   = ws %x2C ws  ; , Comma
const INLINE_TABLE_SEP: char = ',';
// keyval-sep = ws %x3D ws ; =
pub(crate) const KEYVAL_SEP: char = '=';

// inline-table-keyvals = [ inline-table-keyvals-non-empty ]
// inline-table-keyvals-non-empty = ( key keyval-sep val inline-table-sep inline-table-keyvals-non-empty ) /
//                                  ( key keyval-sep val )
parser!{
    fn inline_table_keyvals['a, I]()(I) -> (&'a str, Vec<(InternalString, KeyValue)>)
        where
        [I: RangeStream<Range = &'a str, Item = char>,]
    {
        (
            sep_by(keyval(), char(INLINE_TABLE_SEP)),
            ws(),
        ).map(|(v, w)| {
            (w, v)
        })
    }
}

parser!{
    fn keyval['a, I]()(I) -> (InternalString, KeyValue)
        where
        [I: RangeStream<Range = &'a str, Item = char>,]
    {
        (
            try((ws(), key(), ws())),
            char(KEYVAL_SEP),
            (ws(), value(), ws()),
        ).map(|(k, _, v)| {
            let (pre, v, suf) = v;
            let v = decorated(v, pre, suf);
            let (pre, (raw, key), suf) = k;
            (
                key,
                KeyValue {
                    key: Repr::new(pre, raw, suf),
                    value: v,
                }
            )
        })
    }
}
<commit_msg>fix(fmt): split long line<commit_after>use combine::*;
use combine::char::char;
use combine::primitives::RangeStream;
use parser::errors::CustomError;
use parser::trivia::ws;
use parser::key::key;
use parser::value::value;
use value::{InlineTable, KeyValue};
use decor::{InternalString, Repr};
use formatted::decorated;

// ;; Inline Table

// inline-table = inline-table-open inline-table-keyvals inline-table-close
parse!(inline_table() -> InlineTable, {
    between(char(INLINE_TABLE_OPEN), char(INLINE_TABLE_CLOSE),
            inline_table_keyvals().and_then(|(p, v)| table_from_pairs(p, v)))
});

fn table_from_pairs(
    preamble: &str,
    v: Vec<(InternalString, KeyValue)>,
) -> Result<InlineTable, CustomError> {
    let mut table = InlineTable::default();
    table.preamble = InternalString::from(preamble);

    for (k, kv) in v {
        if table.contains_key(&k) {
            return Err(CustomError::DuplicateKey {
                key: k.into(),
                table: "inline".into(),
            });
        }
        table.key_value_pairs.insert(k, kv);
    }
    Ok(table)
}

// inline-table-open  = %x7B ws     ; {
const INLINE_TABLE_OPEN: char = '{';
// inline-table-close = ws %x7D     ; }
const INLINE_TABLE_CLOSE: char = '}';
// inline-table-sep   = ws %x2C ws  ; , Comma
const INLINE_TABLE_SEP: char = ',';
// keyval-sep = ws %x3D ws ; =
pub(crate) const KEYVAL_SEP: char = '=';

// inline-table-keyvals = [ inline-table-keyvals-non-empty ]
// inline-table-keyvals-non-empty =
// ( key keyval-sep val inline-table-sep inline-table-keyvals-non-empty ) /
// ( key keyval-sep val )
parser!{
    fn inline_table_keyvals['a, I]()(I) -> (&'a str, Vec<(InternalString, KeyValue)>)
        where
        [I: RangeStream<Range = &'a str, Item = char>,]
    {
        (
            sep_by(keyval(), char(INLINE_TABLE_SEP)),
            ws(),
        ).map(|(v, w)| {
            (w, v)
        })
    }
}

parser!{
    fn keyval['a, I]()(I) -> (InternalString, KeyValue)
        where
        [I: RangeStream<Range = &'a str, Item = char>,]
    {
        (
            try((ws(), key(), ws())),
            char(KEYVAL_SEP),
            (ws(), value(), ws()),
        ).map(|(k, _, v)| {
            let (pre, v, suf) = v;
            let v = decorated(v, pre, suf);
            let (pre, (raw, key), suf) = k;
            (
                key,
                KeyValue {
                    key: Repr::new(pre, raw, suf),
                    value: v,
                }
            )
        })
    }
}
<|endoftext|>