<commit_before>use std::fmt;
use crate::decoders::basics::*;

const DECODE_TABLE_BITS: u32 = 11;

pub struct HuffTable {
  // These two fields directly represent the contents of a JPEG DHT marker
  pub bits: [u32;17],
  pub huffval: [u32;256],

  // Represent the weird shifts that are needed for some NEF files
  pub shiftval: [u32;256],

  // The remaining fields are computed from the above to allow more
  // efficient coding and decoding and thus private
  nbits: u32,
  hufftable: Vec<(u16,u16,u16)>,
  decodetable: Vec<Option<(u16,i32)>>,
  pub dng_bug: bool,
  pub initialized: bool,
}

struct MockPump {
  bits: u64,
  nbits: u32,
}

impl MockPump {
  pub fn empty() -> Self {
    MockPump {
      bits: 0,
      nbits: 0,
    }
  }

  pub fn set(&mut self, bits: u32, nbits: u32) {
    self.bits = (bits as u64) << 32;
    self.nbits = nbits + 32;
  }

  pub fn validbits(&self) -> i32 {
    self.nbits as i32 - 32
  }
}

impl BitPump for MockPump {
  fn peek_bits(&mut self, num: u32) -> u32 {
    (self.bits >> (self.nbits-num)) as u32
  }

  fn consume_bits(&mut self, num: u32) {
    self.nbits -= num;
    self.bits &= (1 << self.nbits) - 1;
  }
}

impl HuffTable {
  pub fn empty() -> HuffTable {
    HuffTable {
      bits: [0;17],
      huffval: [0;256],
      shiftval: [0;256],
      nbits: 0,
      hufftable: Vec::new(),
      decodetable: Vec::new(),
      dng_bug: false,
      initialized: false,
    }
  }

  pub fn new(bits: [u32;17], huffval: [u32;256], dng_bug: bool) -> Result<HuffTable,String> {
    let mut tbl = HuffTable {
      bits: bits,
      huffval: huffval,
      shiftval: [0;256],
      nbits: 0,
      hufftable: Vec::new(),
      decodetable: Vec::new(),
      dng_bug: dng_bug,
      initialized: false,
    };
    tbl.initialize()?;
    Ok(tbl)
  }

  pub fn initialize(&mut self) -> Result<(), String> {
    // Create the decoding table for the huffman lengths
    self.nbits = 16;
    for i in 0..16 {
      if self.bits[16-i] != 0 {
        break;
      }
      self.nbits -= 1;
    }

    let tblsize = 1 << self.nbits;
    self.hufftable = vec![(0,0,0); tblsize];

    let mut h = 0;
    let mut pos = 0;
    for len in 0..self.nbits {
      for _ in 0..self.bits[len as usize + 1] {
        for _ in 0..(1 << (self.nbits-len-1)) {
          self.hufftable[h] = (len as u16 + 1, self.huffval[pos] as u16, self.shiftval[pos] as u16);
          h += 1;
        }
        pos += 1;
      }
    }

    // Now bootstrap the full decode table
    let mut pump = MockPump::empty();
    self.decodetable = vec![None; 1 << DECODE_TABLE_BITS];
    let mut i = 0;
    loop {
      pump.set(i, DECODE_TABLE_BITS);
      let res = self.huff_decode_slow(&mut pump);
      let validbits = pump.validbits();
      if validbits >= 0 {
        // We had a valid decode within the lookup bits, save that result to
        // every position where the decode applies.
        for _ in 0..(1 << validbits) {
          self.decodetable[i as usize] = Some(res);
          i += 1;
          if i >= 1 << DECODE_TABLE_BITS {
            break;
          }
        }
      } else {
        i += 1;
      }
      if i >= 1 << DECODE_TABLE_BITS {
        break;
      }
    }

    self.initialized = true;
    Ok(())
  }

  pub fn huff_decode(&self, pump: &mut dyn BitPump) -> Result<i32,String> {
    let code = pump.peek_bits(DECODE_TABLE_BITS) as usize;
    if let Some((bits,decode)) = self.decodetable[code] {
      pump.consume_bits(bits as u32);
      Ok(decode)
    } else {
      let decode = self.huff_decode_slow(pump);
      Ok(decode.1)
    }
  }

  pub fn huff_decode_slow(&self, pump: &mut dyn BitPump) -> (u16,i32) {
    let len = self.huff_len(pump);
    (len.0+len.1, self.huff_diff(pump, len))
  }

  pub fn huff_len(&self, pump: &mut dyn BitPump) -> (u16,u16,u16) {
    let code = pump.peek_bits(self.nbits) as usize;
    let (bits, len, shift) = self.hufftable[code];
    pump.consume_bits(bits as u32);
    (bits, len, shift)
  }

  pub fn huff_diff(&self, pump: &mut dyn BitPump, input: (u16,u16,u16)) -> i32 {
    let (_, len, shift) = input;

    match len {
      0 => 0,
      16 => {
        if self.dng_bug {
          pump.get_bits(16); // consume can fail because we haven't peeked yet
        }
        -32768
      },
      len => {
        // decode the difference and extend sign bit
        let fulllen: i32 = len as i32 + shift as i32;
        let shift: i32 = shift as i32;
        let bits = pump.get_bits(len as u32) as i32;
        let mut diff: i32 = ((bits << 1) + 1) << shift >> 1;
        if (diff & (1 << (fulllen - 1))) == 0 {
          diff -= (1 << fulllen) - ((shift == 0) as i32);
        }
        diff
      },
    }
  }
}

impl fmt::Debug for HuffTable {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    if self.initialized {
      write!(f, "HuffTable {{ bits: {:?} huffval: {:?} }}", self.bits, &self.huffval[..])
    } else {
      write!(f, "HuffTable {{ uninitialized }}")
    }
  }
}
<commit_msg>Extend invalid decodes in huffman table<commit_after>use std::fmt;
use std::cmp;
use crate::decoders::basics::*;

const DECODE_TABLE_BITS: u32 = 11;

pub struct HuffTable {
  // These two fields directly represent the contents of a JPEG DHT marker
  pub bits: [u32;17],
  pub huffval: [u32;256],

  // Represent the weird shifts that are needed for some NEF files
  pub shiftval: [u32;256],

  // The remaining fields are computed from the above to allow more
  // efficient coding and decoding and thus private
  nbits: u32,
  hufftable: Vec<(u16,u16,u16)>,
  decodetable: Vec<Option<(u16,i32)>>,
  pub dng_bug: bool,
  pub initialized: bool,
}

struct MockPump {
  bits: u64,
  nbits: u32,
}

impl MockPump {
  pub fn empty() -> Self {
    MockPump {
      bits: 0,
      nbits: 0,
    }
  }

  pub fn set(&mut self, bits: u32, nbits: u32) {
    self.bits = (bits as u64) << 32;
    self.nbits = nbits + 32;
  }

  pub fn validbits(&self) -> i32 {
    self.nbits as i32 - 32
  }
}

impl BitPump for MockPump {
  fn peek_bits(&mut self, num: u32) -> u32 {
    (self.bits >> (self.nbits-num)) as u32
  }

  fn consume_bits(&mut self, num: u32) {
    self.nbits -= num;
    self.bits &= (1 << self.nbits) - 1;
  }
}

impl HuffTable {
  pub fn empty() -> HuffTable {
    HuffTable {
      bits: [0;17],
      huffval: [0;256],
      shiftval: [0;256],
      nbits: 0,
      hufftable: Vec::new(),
      decodetable: Vec::new(),
      dng_bug: false,
      initialized: false,
    }
  }

  pub fn new(bits: [u32;17], huffval: [u32;256], dng_bug: bool) -> Result<HuffTable,String> {
    let mut tbl = HuffTable {
      bits: bits,
      huffval: huffval,
      shiftval: [0;256],
      nbits: 0,
      hufftable: Vec::new(),
      decodetable: Vec::new(),
      dng_bug: dng_bug,
      initialized: false,
    };
    tbl.initialize()?;
    Ok(tbl)
  }

  pub fn initialize(&mut self) -> Result<(), String> {
    // Create the decoding table for the huffman lengths
    self.nbits = 16;
    for i in 0..16 {
      if self.bits[16-i] != 0 {
        break;
      }
      self.nbits -= 1;
    }

    let tblsize = 1 << self.nbits;
    self.hufftable = vec![(0,0,0); tblsize];

    let mut h = 0;
    let mut pos = 0;
    for len in 0..self.nbits {
      for _ in 0..self.bits[len as usize + 1] {
        for _ in 0..(1 << (self.nbits-len-1)) {
          self.hufftable[h] = (len as u16 + 1, self.huffval[pos] as u16, self.shiftval[pos] as u16);
          h += 1;
        }
        pos += 1;
      }
    }

    // Now bootstrap the full decode table
    let mut pump = MockPump::empty();
    self.decodetable = vec![None; 1 << DECODE_TABLE_BITS];
    let mut i = 0;
    loop {
      pump.set(i, DECODE_TABLE_BITS);
      let (lenbits, totalbits, decode) = self.huff_decode_slow(&mut pump);
      let validbits = pump.validbits();
      if validbits >= 0 {
        // We had a valid decode within the lookup bits, save that result to
        // every position where the decode applies.
        for _ in 0..(1 << validbits) {
          self.decodetable[i as usize] = Some((totalbits, decode));
          i += 1;
          if i >= 1 << DECODE_TABLE_BITS {
            break;
          }
        }
      } else {
        // We had an invalid decode, we can skip as many positions as the ones
        // that have the same bits for length
        i += 1 << cmp::max(0, DECODE_TABLE_BITS - (lenbits as u32));
      }
      if i >= 1 << DECODE_TABLE_BITS {
        break;
      }
    }

    self.initialized = true;
    Ok(())
  }

  pub fn huff_decode(&self, pump: &mut dyn BitPump) -> Result<i32,String> {
    let code = pump.peek_bits(DECODE_TABLE_BITS) as usize;
    if let Some((bits,decode)) = self.decodetable[code] {
      pump.consume_bits(bits as u32);
      Ok(decode)
    } else {
      let decode = self.huff_decode_slow(pump);
      Ok(decode.2)
    }
  }

  pub fn huff_decode_slow(&self, pump: &mut dyn BitPump) -> (u16, u16,i32) {
    let len = self.huff_len(pump);
    (len.0, len.0+len.1, self.huff_diff(pump, len))
  }

  pub fn huff_len(&self, pump: &mut dyn BitPump) -> (u16,u16,u16) {
    let code = pump.peek_bits(self.nbits) as usize;
    let (bits, len, shift) = self.hufftable[code];
    pump.consume_bits(bits as u32);
    (bits, len, shift)
  }

  pub fn huff_diff(&self, pump: &mut dyn BitPump, input: (u16,u16,u16)) -> i32 {
    let (_, len, shift) = input;

    match len {
      0 => 0,
      16 => {
        if self.dng_bug {
          pump.get_bits(16); // consume can fail because we haven't peeked yet
        }
        -32768
      },
      len => {
        // decode the difference and extend sign bit
        let fulllen: i32 = len as i32 + shift as i32;
        let shift: i32 = shift as i32;
        let bits = pump.get_bits(len as u32) as i32;
        let mut diff: i32 = ((bits << 1) + 1) << shift >> 1;
        if (diff & (1 << (fulllen - 1))) == 0 {
          diff -= (1 << fulllen) - ((shift == 0) as i32);
        }
        diff
      },
    }
  }
}

impl fmt::Debug for HuffTable {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    if self.initialized {
      write!(f, "HuffTable {{ bits: {:?} huffval: {:?} }}", self.bits, &self.huffval[..])
    } else {
      write!(f, "HuffTable {{ uninitialized }}")
    }
  }
}
<|endoftext|>


<commit_before>use futures::executor::block_on;
use futures::future::{self, FutureExt, BoxFuture};
use std::sync::mpsc;
use std::thread;

#[test]
fn lots() {
    fn do_it(input: (i32, i32)) -> BoxFuture<'static, i32> {
        let (n, x) = input;
        if n == 0 {
            future::ready(x).boxed()
        } else {
            future::ready((n - 1, x + n)).then(do_it).boxed()
        }
    }

    let (tx, rx) = mpsc::channel();
    thread::spawn(|| {
        block_on(do_it((1_000, 0)).map(move |x| tx.send(x).unwrap()))
    });
    assert_eq!(500_500, rx.recv().unwrap());
}
<commit_msg>futures: tests/ready_queue.rs: Don't break w/o "executor"<commit_after>#[cfg(feature = "executor")] // executor::
#[test]
fn lots() {
    use futures::executor::block_on;
    use futures::future::{self, FutureExt, BoxFuture};
    use std::sync::mpsc;
    use std::thread;

    fn do_it(input: (i32, i32)) -> BoxFuture<'static, i32> {
        let (n, x) = input;
        if n == 0 {
            future::ready(x).boxed()
        } else {
            future::ready((n - 1, x + n)).then(do_it).boxed()
        }
    }

    let (tx, rx) = mpsc::channel();
    thread::spawn(|| {
        block_on(do_it((1_000, 0)).map(move |x| tx.send(x).unwrap()))
    });
    assert_eq!(500_500, rx.recv().unwrap());
}
<|endoftext|>


<commit_before>//! Information about varying calling conventions.

use il;
use types::PartialBoolean;
use std::collections::HashSet;

/// Available type of calling conventions
pub enum CallingConventionType {
    MipsSystemV,
    MipselSystemV,
    Cdecl
}

/// The return type for a function.
pub enum ReturnAddressType {
    /// Functions return by loading an address from a register.
    Register(il::Scalar),
    /// Functions return by loading an address from the stack.
    ///
    /// The offset to the return address at function call/entry is given.
    Stack(usize)
}

/// The type of an argument.
pub enum ArgumentType {
    /// The argument is held in a register.
    Register(il::Scalar),

    /// The argument is held in a stack offset.
    ///
    /// The stack offset is given at function call/entry.
    Stack(usize)
}

/// Represents the calling convention of a particular platform.
pub struct CallingConvention {
    /// arguments passed in registers.
    argument_registers: Vec<il::Scalar>,

    /// These registers are preserved across function calls.
    preserved_registers: HashSet<il::Scalar>,

    /// These registers are not preserved across function calls.
    trashed_registers: HashSet<il::Scalar>,

    /// Offset from function start where first argument on stack is found.
    ///
    /// After register arguments are exhausted, analysis will begin looking
    /// here.
    stack_argument_offset: usize,

    /// Length of an argument on the stack in bytes.
    stack_argument_length: usize,

    /// The return address is given in the following type.
    return_address_type: ReturnAddressType,

    /// The register the returned value is given in.
    return_register: il::Scalar
}

/*
    Mips System V:
        $16-$23 and $29-$31 are saved. This is $s0-S8, $sp and $ra.
        Result is in $v0.
        Everything else is trashed.
*/

impl CallingConvention {
    /// Create a new `CallingConvention` based on the given
    /// `CallingConventionType`.
    pub fn new(typ: CallingConventionType) -> CallingConvention {
        match typ {
            CallingConventionType::MipsSystemV |
            CallingConventionType::MipselSystemV => {
                let argument_registers = vec![
                    il::scalar("$a0", 32), il::scalar("$a1", 32),
                    il::scalar("$a2", 32), il::scalar("$a3", 32)
                ];

                let mut preserved_registers = HashSet::new();
                preserved_registers.insert(il::scalar("$s0", 32));
                preserved_registers.insert(il::scalar("$s1", 32));
                preserved_registers.insert(il::scalar("$s2", 32));
                preserved_registers.insert(il::scalar("$s3", 32));
                preserved_registers.insert(il::scalar("$s4", 32));
                preserved_registers.insert(il::scalar("$s5", 32));
                preserved_registers.insert(il::scalar("$s6", 32));
                preserved_registers.insert(il::scalar("$s7", 32));
                preserved_registers.insert(il::scalar("$s8", 32));
                preserved_registers.insert(il::scalar("$sp", 32));
                preserved_registers.insert(il::scalar("$ra", 32));

                let mut trashed_registers = HashSet::new();
                trashed_registers.insert(il::scalar("$at", 32));
                trashed_registers.insert(il::scalar("$v0", 32));
                trashed_registers.insert(il::scalar("$v1", 32));
                trashed_registers.insert(il::scalar("$a0", 32));
                trashed_registers.insert(il::scalar("$a1", 32));
                trashed_registers.insert(il::scalar("$a2", 32));
                trashed_registers.insert(il::scalar("$a3", 32));
                trashed_registers.insert(il::scalar("$t0", 32));
                trashed_registers.insert(il::scalar("$t1", 32));
                trashed_registers.insert(il::scalar("$t2", 32));
                trashed_registers.insert(il::scalar("$t3", 32));
                trashed_registers.insert(il::scalar("$t4", 32));
                trashed_registers.insert(il::scalar("$t5", 32));
                trashed_registers.insert(il::scalar("$t6", 32));
                trashed_registers.insert(il::scalar("$t7", 32));
                trashed_registers.insert(il::scalar("$t8", 32));
                trashed_registers.insert(il::scalar("$t9", 32));

                let return_type = ReturnAddressType::Register(il::scalar("$ra", 32));

                CallingConvention {
                    argument_registers: argument_registers,
                    preserved_registers: preserved_registers,
                    trashed_registers: trashed_registers,
                    stack_argument_offset: 0,
                    stack_argument_length: 4,
                    return_address_type: return_type,
                    return_register: il::scalar("$v0", 32)
                }
            },
            CallingConventionType::Cdecl => {
                let mut preserved_registers = HashSet::new();
                preserved_registers.insert(il::scalar("ebx", 32));
                preserved_registers.insert(il::scalar("edi", 32));
                preserved_registers.insert(il::scalar("esi", 32));
                preserved_registers.insert(il::scalar("ebp", 32));
                preserved_registers.insert(il::scalar("esp", 32));

                let mut trashed_registers = HashSet::new();
                trashed_registers.insert(il::scalar("eax", 32));
                trashed_registers.insert(il::scalar("ecx", 32));
                trashed_registers.insert(il::scalar("edx", 32));

                let return_type = ReturnAddressType::Register(il::scalar("esp", 32));

                CallingConvention {
                    argument_registers: Vec::new(),
                    preserved_registers: preserved_registers,
                    trashed_registers: trashed_registers,
                    stack_argument_offset: 4,
                    stack_argument_length: 4,
                    return_address_type: return_type,
                    return_register: il::scalar("eax", 32)
                }
            },
        }
    }

    /// Get the registers the first n arguments are passed in.
    pub fn argument_registers(&self) -> &[il::Scalar] {
        &self.argument_registers
    }

    /// Get the registers preserved across function calls.
    pub fn preserved_registers(&self) -> &HashSet<il::Scalar> {
        &self.preserved_registers
    }

    /// Get the registers trashed across function calls.
    pub fn trashed_registers(&self) -> &HashSet<il::Scalar> {
        &self.trashed_registers
    }

    /// Get the length of an argument on the stack in _bytes, not bits_.
    ///
    /// We would expect this to be natural register-width of the architecture.
    pub fn stack_argument_length(&self) -> usize {
        self.stack_argument_length
    }

    /// Get the stack offset to the first argument passed on the stack in
    /// _bytes, not bits_.
    ///
    /// We would expect this to be immediately above the return address, if the
    /// return address is stored on the stack.
    pub fn stack_argument_offset(&self) -> usize {
        self.stack_argument_offset
    }

    /// How the return address is specified for function calls.
    pub fn return_address_type(&self) -> &ReturnAddressType {
        &self.return_address_type
    }

    /// The register returned values is given in.
    pub fn return_register(&self) -> &il::Scalar {
        &self.return_register
    }

    /// Get the type for the given argument, starting with 0 index.
    pub fn argument_type(&self, argument_number: usize) -> ArgumentType {
        if argument_number >= self.argument_registers.len() {
            let n = argument_number - self.argument_registers.len();
            let offset = self.stack_argument_offset + (self.stack_argument_length * n);
            ArgumentType::Stack(offset)
        }
        else {
            ArgumentType::Register(self.argument_registers[argument_number].clone())
        }
    }

    /// Is the given register preserved.
    pub fn is_preserved(&self, scalar: &il::Scalar) -> PartialBoolean {
        if self.preserved_registers.contains(scalar) {
            PartialBoolean::True
        }
        else if self.trashed_registers.contains(scalar) {
            PartialBoolean::False
        }
        else {
            PartialBoolean::Unknown
        }
    }

    /// Is the given register trashed.
    pub fn is_trashed(&self, scalar: &il::Scalar) -> PartialBoolean {
        if self.trashed_registers.contains(scalar) {
            PartialBoolean::True
        }
        else if self.preserved_registers.contains(scalar) {
            PartialBoolean::False
        }
        else {
            PartialBoolean::Unknown
        }
    }
}<commit_msg>derive some traits for calling conventions<commit_after>//! Information about varying calling conventions.

use il;
use types::PartialBoolean;
use std::collections::HashSet;

/// Available type of calling conventions
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum CallingConventionType {
    MipsSystemV,
    MipselSystemV,
    Cdecl
}

/// The return type for a function.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ReturnAddressType {
    /// Functions return by loading an address from a register.
    Register(il::Scalar),
    /// Functions return by loading an address from the stack.
    ///
    /// The offset to the return address at function call/entry is given.
    Stack(usize)
}

/// The type of an argument.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ArgumentType {
    /// The argument is held in a register.
    Register(il::Scalar),

    /// The argument is held in a stack offset.
    ///
    /// The stack offset is given at function call/entry.
    Stack(usize)
}

/// Represents the calling convention of a particular platform.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CallingConvention {
    /// arguments passed in registers.
    argument_registers: Vec<il::Scalar>,

    /// These registers are preserved across function calls.
    preserved_registers: HashSet<il::Scalar>,

    /// These registers are not preserved across function calls.
    trashed_registers: HashSet<il::Scalar>,

    /// Offset from function start where first argument on stack is found.
    ///
    /// After register arguments are exhausted, analysis will begin looking
    /// here.
    stack_argument_offset: usize,

    /// Length of an argument on the stack in bytes.
    stack_argument_length: usize,

    /// The return address is given in the following type.
    return_address_type: ReturnAddressType,

    /// The register the returned value is given in.
    return_register: il::Scalar
}

/*
    Mips System V:
        $16-$23 and $29-$31 are saved. This is $s0-S8, $sp and $ra.
        Result is in $v0.
        Everything else is trashed.
*/

impl CallingConvention {
    /// Create a new `CallingConvention` based on the given
    /// `CallingConventionType`.
    pub fn new(typ: CallingConventionType) -> CallingConvention {
        match typ {
            CallingConventionType::MipsSystemV |
            CallingConventionType::MipselSystemV => {
                let argument_registers = vec![
                    il::scalar("$a0", 32), il::scalar("$a1", 32),
                    il::scalar("$a2", 32), il::scalar("$a3", 32)
                ];

                let mut preserved_registers = HashSet::new();
                preserved_registers.insert(il::scalar("$s0", 32));
                preserved_registers.insert(il::scalar("$s1", 32));
                preserved_registers.insert(il::scalar("$s2", 32));
                preserved_registers.insert(il::scalar("$s3", 32));
                preserved_registers.insert(il::scalar("$s4", 32));
                preserved_registers.insert(il::scalar("$s5", 32));
                preserved_registers.insert(il::scalar("$s6", 32));
                preserved_registers.insert(il::scalar("$s7", 32));
                preserved_registers.insert(il::scalar("$s8", 32));
                preserved_registers.insert(il::scalar("$sp", 32));
                preserved_registers.insert(il::scalar("$ra", 32));

                let mut trashed_registers = HashSet::new();
                trashed_registers.insert(il::scalar("$at", 32));
                trashed_registers.insert(il::scalar("$v0", 32));
                trashed_registers.insert(il::scalar("$v1", 32));
                trashed_registers.insert(il::scalar("$a0", 32));
                trashed_registers.insert(il::scalar("$a1", 32));
                trashed_registers.insert(il::scalar("$a2", 32));
                trashed_registers.insert(il::scalar("$a3", 32));
                trashed_registers.insert(il::scalar("$t0", 32));
                trashed_registers.insert(il::scalar("$t1", 32));
                trashed_registers.insert(il::scalar("$t2", 32));
                trashed_registers.insert(il::scalar("$t3", 32));
                trashed_registers.insert(il::scalar("$t4", 32));
                trashed_registers.insert(il::scalar("$t5", 32));
                trashed_registers.insert(il::scalar("$t6", 32));
                trashed_registers.insert(il::scalar("$t7", 32));
                trashed_registers.insert(il::scalar("$t8", 32));
                trashed_registers.insert(il::scalar("$t9", 32));

                let return_type = ReturnAddressType::Register(il::scalar("$ra", 32));

                CallingConvention {
                    argument_registers: argument_registers,
                    preserved_registers: preserved_registers,
                    trashed_registers: trashed_registers,
                    stack_argument_offset: 0,
                    stack_argument_length: 4,
                    return_address_type: return_type,
                    return_register: il::scalar("$v0", 32)
                }
            },
            CallingConventionType::Cdecl => {
                let mut preserved_registers = HashSet::new();
                preserved_registers.insert(il::scalar("ebx", 32));
                preserved_registers.insert(il::scalar("edi", 32));
                preserved_registers.insert(il::scalar("esi", 32));
                preserved_registers.insert(il::scalar("ebp", 32));
                preserved_registers.insert(il::scalar("esp", 32));

                let mut trashed_registers = HashSet::new();
                trashed_registers.insert(il::scalar("eax", 32));
                trashed_registers.insert(il::scalar("ecx", 32));
                trashed_registers.insert(il::scalar("edx", 32));

                let return_type = ReturnAddressType::Register(il::scalar("esp", 32));

                CallingConvention {
                    argument_registers: Vec::new(),
                    preserved_registers: preserved_registers,
                    trashed_registers: trashed_registers,
                    stack_argument_offset: 4,
                    stack_argument_length: 4,
                    return_address_type: return_type,
                    return_register: il::scalar("eax", 32)
                }
            },
        }
    }

    /// Get the registers the first n arguments are passed in.
    pub fn argument_registers(&self) -> &[il::Scalar] {
        &self.argument_registers
    }

    /// Get the registers preserved across function calls.
    pub fn preserved_registers(&self) -> &HashSet<il::Scalar> {
        &self.preserved_registers
    }

    /// Get the registers trashed across function calls.
    pub fn trashed_registers(&self) -> &HashSet<il::Scalar> {
        &self.trashed_registers
    }

    /// Get the length of an argument on the stack in _bytes, not bits_.
    ///
    /// We would expect this to be natural register-width of the architecture.
    pub fn stack_argument_length(&self) -> usize {
        self.stack_argument_length
    }

    /// Get the stack offset to the first argument passed on the stack in
    /// _bytes, not bits_.
    ///
    /// We would expect this to be immediately above the return address, if the
    /// return address is stored on the stack.
    pub fn stack_argument_offset(&self) -> usize {
        self.stack_argument_offset
    }

    /// How the return address is specified for function calls.
    pub fn return_address_type(&self) -> &ReturnAddressType {
        &self.return_address_type
    }

    /// The register returned values is given in.
    pub fn return_register(&self) -> &il::Scalar {
        &self.return_register
    }

    /// Get the type for the given argument, starting with 0 index.
    pub fn argument_type(&self, argument_number: usize) -> ArgumentType {
        if argument_number >= self.argument_registers.len() {
            let n = argument_number - self.argument_registers.len();
            let offset = self.stack_argument_offset + (self.stack_argument_length * n);
            ArgumentType::Stack(offset)
        }
        else {
            ArgumentType::Register(self.argument_registers[argument_number].clone())
        }
    }

    /// Is the given register preserved.
    pub fn is_preserved(&self, scalar: &il::Scalar) -> PartialBoolean {
        if self.preserved_registers.contains(scalar) {
            PartialBoolean::True
        }
        else if self.trashed_registers.contains(scalar) {
            PartialBoolean::False
        }
        else {
            PartialBoolean::Unknown
        }
    }

    /// Is the given register trashed.
    pub fn is_trashed(&self, scalar: &il::Scalar) -> PartialBoolean {
        if self.trashed_registers.contains(scalar) {
            PartialBoolean::True
        }
        else if self.preserved_registers.contains(scalar) {
            PartialBoolean::False
        }
        else {
            PartialBoolean::Unknown
        }
    }
}<|endoftext|>


<commit_before>use std::ops::Deref;
use std::ops::DerefMut;

use itertools::Itertools;

use libimagstore::store::{Entry, EntryHeader, FileLockEntry};
use libimagerror::into::IntoError;

use error::TagErrorKind;
use error::MapErrInto;
use result::Result;
use tag::{Tag, TagSlice};
use util::is_tag;

use toml::Value;

pub trait Tagable {

    fn get_tags(&self) -> Result<Vec<Tag>>;
    fn set_tags(&mut self, ts: &[Tag]) -> Result<()>;

    fn add_tag(&mut self, t: Tag) -> Result<()>;
    fn remove_tag(&mut self, t: Tag) -> Result<()>;

    fn has_tag(&self, t: TagSlice) -> Result<bool>;
    fn has_tags(&self, ts: &[Tag]) -> Result<bool>;

}

impl Tagable for EntryHeader {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(kind.into_error_with_cause(Box::new(tags.unwrap_err())));
        }
        let tags = tags.unwrap();

        match tags {
            Some(Value::Array(tags)) => {
                if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
                    return Err(TagErrorKind::TagTypeError.into());
                }
                if tags.iter().any(|t| match *t {
                    Value::String(ref s) => !is_tag(s),
                    _ => unreachable!()})
                {
                    return Err(TagErrorKind::NotATag.into());
                }

                Ok(tags.iter()
                    .cloned()
                    .map(|t| {
                        match t {
                           Value::String(s) => s,
                           _ => unreachable!(),
                        }
                    })
                    .collect())
            },
            None => Ok(vec![]),
            _ => Err(TagErrorKind::TagTypeError.into()),
        }
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        if ts.iter().any(|tag| !is_tag(tag)) {
            debug!("Not a tag: '{}'", ts.iter().filter(|t| !is_tag(t)).next().unwrap());
            return Err(TagErrorKind::NotATag.into());
        }

        let a = ts.iter().unique().map(|t| Value::String(t.clone())).collect();
        self.set("imag.tags", Value::Array(a))
            .map(|_| ())
            .map_err(Box::new)
            .map_err(|e| TagErrorKind::HeaderWriteError.into_error_with_cause(e))
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.push(t);
                self.set_tags(&tags.into_iter().unique().collect::<Vec<_>>()[..])
            })
            .map(|_| ())
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.retain(|tag| tag.clone() != t);
                self.set_tags(&tags[..])
            })
            .map(|_| ())
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(kind.into_error_with_cause(Box::new(tags.unwrap_err())));
        }
        let tags = tags.unwrap();

        if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
            return Err(TagErrorKind::TagTypeError.into());
        }

        Ok(tags
           .iter()
           .any(|tag| {
               match *tag {
                   Value::String(ref s) => { s == t },
                   _ => unreachable!()
               }
           }))
    }

    fn has_tags(&self, tags: &[Tag]) -> Result<bool> {
        let mut result = true;
        for tag in tags {
            let check = self.has_tag(tag);
            if check.is_err() {
                return Err(check.unwrap_err());
            }
            let check = check.unwrap();

            result = result && check;
        }

        Ok(result)
    }

}

impl Tagable for Entry {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.get_header().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.get_header_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.get_header().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.get_header().has_tags(ts)
    }

}

impl<'a> Tagable for FileLockEntry<'a> {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.deref().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.deref_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.deref_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.deref_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.deref().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.deref().has_tags(ts)
    }

}

<commit_msg>Replace unwrap() with try!()<commit_after>use std::ops::Deref;
use std::ops::DerefMut;

use itertools::Itertools;

use libimagstore::store::{Entry, EntryHeader, FileLockEntry};
use libimagerror::into::IntoError;

use error::TagErrorKind;
use error::MapErrInto;
use result::Result;
use tag::{Tag, TagSlice};
use util::is_tag;

use toml::Value;

pub trait Tagable {

    fn get_tags(&self) -> Result<Vec<Tag>>;
    fn set_tags(&mut self, ts: &[Tag]) -> Result<()>;

    fn add_tag(&mut self, t: Tag) -> Result<()>;
    fn remove_tag(&mut self, t: Tag) -> Result<()>;

    fn has_tag(&self, t: TagSlice) -> Result<bool>;
    fn has_tags(&self, ts: &[Tag]) -> Result<bool>;

}

impl Tagable for EntryHeader {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));

        match tags {
            Some(Value::Array(tags)) => {
                if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
                    return Err(TagErrorKind::TagTypeError.into());
                }
                if tags.iter().any(|t| match *t {
                    Value::String(ref s) => !is_tag(s),
                    _ => unreachable!()})
                {
                    return Err(TagErrorKind::NotATag.into());
                }

                Ok(tags.iter()
                    .cloned()
                    .map(|t| {
                        match t {
                           Value::String(s) => s,
                           _ => unreachable!(),
                        }
                    })
                    .collect())
            },
            None => Ok(vec![]),
            _ => Err(TagErrorKind::TagTypeError.into()),
        }
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        if ts.iter().any(|tag| !is_tag(tag)) {
            debug!("Not a tag: '{}'", ts.iter().filter(|t| !is_tag(t)).next().unwrap());
            return Err(TagErrorKind::NotATag.into());
        }

        let a = ts.iter().unique().map(|t| Value::String(t.clone())).collect();
        self.set("imag.tags", Value::Array(a))
            .map(|_| ())
            .map_err(Box::new)
            .map_err(|e| TagErrorKind::HeaderWriteError.into_error_with_cause(e))
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.push(t);
                self.set_tags(&tags.into_iter().unique().collect::<Vec<_>>()[..])
            })
            .map(|_| ())
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.retain(|tag| tag.clone() != t);
                self.set_tags(&tags[..])
            })
            .map(|_| ())
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(kind.into_error_with_cause(Box::new(tags.unwrap_err())));
        }
        let tags = tags.unwrap();

        if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
            return Err(TagErrorKind::TagTypeError.into());
        }

        Ok(tags
           .iter()
           .any(|tag| {
               match *tag {
                   Value::String(ref s) => { s == t },
                   _ => unreachable!()
               }
           }))
    }

    fn has_tags(&self, tags: &[Tag]) -> Result<bool> {
        let mut result = true;
        for tag in tags {
            let check = self.has_tag(tag);
            if check.is_err() {
                return Err(check.unwrap_err());
            }
            let check = check.unwrap();

            result = result && check;
        }

        Ok(result)
    }

}

impl Tagable for Entry {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.get_header().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.get_header_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.get_header().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.get_header().has_tags(ts)
    }

}

impl<'a> Tagable for FileLockEntry<'a> {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.deref().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.deref_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.deref_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.deref_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.deref().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.deref().has_tags(ts)
    }

}

<|endoftext|>


<commit_before>use crate::crate_disambiguator::CrateDisambiguator;
use crate::HashStableContext;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_data_structures::AtomicRef;
use rustc_index::vec::Idx;
use rustc_macros::HashStable_Generic;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::borrow::Borrow;
use std::fmt;

rustc_index::newtype_index! {
    pub struct CrateNum {
        ENCODABLE = custom
        DEBUG_FORMAT = "crate{}"
    }
}

/// Item definitions in the currently-compiled crate would have the `CrateNum`
/// `LOCAL_CRATE` in their `DefId`.
pub const LOCAL_CRATE: CrateNum = CrateNum::from_u32(0);

impl CrateNum {
    #[inline]
    pub fn new(x: usize) -> CrateNum {
        CrateNum::from_usize(x)
    }

    #[inline]
    pub fn as_def_id(&self) -> DefId {
        DefId { krate: *self, index: CRATE_DEF_INDEX }
    }
}

impl fmt::Display for CrateNum {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.private, f)
    }
}

/// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx.
/// Therefore, make sure to include the context when encode a `CrateNum`.
impl<E: Encoder> Encodable<E> for CrateNum {
    default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
        s.emit_u32(self.as_u32())
    }
}

impl<D: Decoder> Decodable<D> for CrateNum {
    default fn decode(d: &mut D) -> Result<CrateNum, D::Error> {
        Ok(CrateNum::from_u32(d.read_u32()?))
    }
}

/// A `DefPathHash` is a fixed-size representation of a `DefPath` that is
/// stable across crate and compilation session boundaries. It consists of two
/// separate 64-bit hashes. The first uniquely identifies the crate this
/// `DefPathHash` originates from (see [StableCrateId]), and the second
/// uniquely identifies the corresponding `DefPath` within that crate. Together
/// they form a unique identifier within an entire crate graph.
///
/// There is a very small chance of hash collisions, which would mean that two
/// different `DefPath`s map to the same `DefPathHash`. Proceeding compilation
/// with such a hash collision would very probably lead to an ICE, and in the
/// worst case lead to a silent mis-compilation. The compiler therefore actively
/// and exhaustively checks for such hash collisions and aborts compilation if
/// it finds one.
///
/// `DefPathHash` uses 64-bit hashes for both the crate-id part and the
/// crate-internal part, even though it is likely that there are many more
/// `LocalDefId`s in a single crate than there are individual crates in a crate
/// graph. Since we use the same number of bits in both cases, the collision
/// probability for the crate-local part will be quite a bit higher (though
/// still very small).
///
/// This imbalance is not by accident: A hash collision in the
/// crate-local part of a `DefPathHash` will be detected and reported while
/// compiling the crate in question. Such a collision does not depend on
/// outside factors and can be easily fixed by the crate maintainer (e.g. by
/// renaming the item in question or by bumping the crate version in a harmless
/// way).
///
/// A collision between crate-id hashes on the other hand is harder to fix
/// because it depends on the set of crates in the entire crate graph of a
/// compilation session. Again, using the same crate with a different version
/// number would fix the issue with a high probability -- but that might be
/// easier said then done if the crates in questions are dependencies of
/// third-party crates.
///
/// That being said, given a high quality hash function, the collision
/// probabilities in question are very small. For example, for a big crate like
/// `rustc_middle` (with ~50000 `LocalDefId`s as of the time of writing) there
/// is a probability of roughly 1 in 14,750,000,000 of a crate-internal
/// collision occurring. For a big crate graph with 1000 crates in it, there is
/// a probability of 1 in 36,890,000,000,000 of a `StableCrateId` collision.
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[derive(HashStable_Generic, Encodable, Decodable)]
pub struct DefPathHash(pub Fingerprint);

impl DefPathHash {
    /// Returns the [StableCrateId] identifying the crate this [DefPathHash]
    /// originates from.
    #[inline]
    pub fn stable_crate_id(&self) -> StableCrateId {
        StableCrateId(self.0.as_value().0)
    }

    /// Returns the crate-local part of the [DefPathHash].
    ///
    /// Used for tests.
    #[inline]
    pub fn local_hash(&self) -> u64 {
        self.0.as_value().1
    }

    /// Builds a new [DefPathHash] with the given [StableCrateId] and
    /// `local_hash`, where `local_hash` must be unique within its crate.
    pub fn new(stable_crate_id: StableCrateId, local_hash: u64) -> DefPathHash {
        DefPathHash(Fingerprint::new(stable_crate_id.0, local_hash))
    }
}

impl Borrow<Fingerprint> for DefPathHash {
    #[inline]
    fn borrow(&self) -> &Fingerprint {
        &self.0
    }
}

/// A [StableCrateId] is a 64 bit hash of `(crate-name, crate-disambiguator)`. It
/// is to [CrateNum] what [DefPathHash] is to [DefId]. It is stable across
/// compilation sessions.
///
/// Since the ID is a hash value there is a (very small) chance that two crates
/// end up with the same [StableCrateId]. The compiler will check for such
/// collisions when loading crates and abort compilation in order to avoid
/// further trouble.
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Encodable, Decodable)]
pub struct StableCrateId(u64);

impl StableCrateId {
    /// Computes the stable ID for a crate with the given name and
    /// disambiguator.
    pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> StableCrateId {
        use std::hash::Hash;

        let mut hasher = StableHasher::new();
        crate_name.hash(&mut hasher);
        crate_disambiguator.hash(&mut hasher);
        StableCrateId(hasher.finish())
    }
}

rustc_index::newtype_index! {
    /// A DefIndex is an index into the hir-map for a crate, identifying a
    /// particular definition. It should really be considered an interned
    /// shorthand for a particular DefPath.
    pub struct DefIndex {
        ENCODABLE = custom // (only encodable in metadata)

        DEBUG_FORMAT = "DefIndex({})",
        /// The crate root is always assigned index 0 by the AST Map code,
        /// thanks to `NodeCollector::new`.
        const CRATE_DEF_INDEX = 0,
    }
}

impl<E: Encoder> Encodable<E> for DefIndex {
    default fn encode(&self, _: &mut E) -> Result<(), E::Error> {
        panic!("cannot encode `DefIndex` with `{}`", std::any::type_name::<E>());
    }
}

impl<D: Decoder> Decodable<D> for DefIndex {
    default fn decode(_: &mut D) -> Result<DefIndex, D::Error> {
        panic!("cannot decode `DefIndex` with `{}`", std::any::type_name::<D>());
    }
}

/// A `DefId` identifies a particular *definition*, by combining a crate
/// index and a def index.
///
/// You can create a `DefId` from a `LocalDefId` using `local_def_id.to_def_id()`.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
pub struct DefId {
    pub krate: CrateNum,
    pub index: DefIndex,
}

impl DefId {
    /// Makes a local `DefId` from the given `DefIndex`.
    #[inline]
    pub fn local(index: DefIndex) -> DefId {
        DefId { krate: LOCAL_CRATE, index }
    }

    /// Returns whether the item is defined in the crate currently being compiled.
    #[inline]
    pub fn is_local(self) -> bool {
        self.krate == LOCAL_CRATE
    }

    #[inline]
    pub fn as_local(self) -> Option<LocalDefId> {
        if self.is_local() { Some(LocalDefId { local_def_index: self.index }) } else { None }
    }

    #[inline]
    pub fn expect_local(self) -> LocalDefId {
        self.as_local().unwrap_or_else(|| panic!("DefId::expect_local: `{:?}` isn't local", self))
    }

    pub fn is_top_level_module(self) -> bool {
        self.is_local() && self.index == CRATE_DEF_INDEX
    }
}

impl<E: Encoder> Encodable<E> for DefId {
    default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
        s.emit_struct(false, |s| {
            s.emit_struct_field("krate", true, |s| self.krate.encode(s))?;

            s.emit_struct_field("index", false, |s| self.index.encode(s))
        })
    }
}

impl<D: Decoder> Decodable<D> for DefId {
    default fn decode(d: &mut D) -> Result<DefId, D::Error> {
        d.read_struct(|d| {
            Ok(DefId {
                krate: d.read_struct_field("krate", Decodable::decode)?,
                index: d.read_struct_field("index", Decodable::decode)?,
            })
        })
    }
}

pub fn default_def_id_debug(def_id: DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    f.debug_struct("DefId").field("krate", &def_id.krate).field("index", &def_id.index).finish()
}

pub static DEF_ID_DEBUG: AtomicRef<fn(DefId, &mut fmt::Formatter<'_>) -> fmt::Result> =
    AtomicRef::new(&(default_def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));

impl fmt::Debug for DefId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        (*DEF_ID_DEBUG)(*self, f)
    }
}

rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefId);

/// A LocalDefId is equivalent to a DefId with `krate == LOCAL_CRATE`. Since
/// we encode this information in the type, we can ensure at compile time that
/// no DefIds from upstream crates get thrown into the mix. There are quite a
/// few cases where we know that only DefIds from the local crate are expected
/// and a DefId from a different crate would signify a bug somewhere. This
/// is when LocalDefId comes in handy.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LocalDefId {
    pub local_def_index: DefIndex,
}

pub const CRATE_DEF_ID: LocalDefId = LocalDefId { local_def_index: CRATE_DEF_INDEX };

impl Idx for LocalDefId {
    #[inline]
    fn new(idx: usize) -> Self {
        LocalDefId { local_def_index: Idx::new(idx) }
    }
    #[inline]
    fn index(self) -> usize {
        self.local_def_index.index()
    }
}

impl LocalDefId {
    #[inline]
    pub fn to_def_id(self) -> DefId {
        DefId { krate: LOCAL_CRATE, index: self.local_def_index }
    }

    #[inline]
    pub fn is_top_level_module(self) -> bool {
        self.local_def_index == CRATE_DEF_INDEX
    }
}

impl fmt::Debug for LocalDefId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.to_def_id().fmt(f)
    }
}

impl<E: Encoder> Encodable<E> for LocalDefId {
    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
        self.to_def_id().encode(s)
    }
}

impl<D: Decoder> Decodable<D> for LocalDefId {
    fn decode(d: &mut D) -> Result<LocalDefId, D::Error> {
        DefId::decode(d).map(|d| d.expect_local())
    }
}

rustc_data_structures::define_id_collections!(LocalDefIdMap, LocalDefIdSet, LocalDefId);

impl<CTX: HashStableContext> HashStable<CTX> for DefId {
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
        hcx.def_path_hash(*self).hash_stable(hcx, hasher);
    }
}

impl<CTX: HashStableContext> HashStable<CTX> for LocalDefId {
    #[inline]
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
        hcx.def_path_hash(self.to_def_id()).hash_stable(hcx, hasher);
    }
}

impl<CTX: HashStableContext> HashStable<CTX> for CrateNum {
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
        hcx.def_path_hash(DefId { krate: *self, index: CRATE_DEF_INDEX }).hash_stable(hcx, hasher);
    }
}

impl<CTX: HashStableContext> ToStableHashKey<CTX> for DefId {
    type KeyType = DefPathHash;

    #[inline]
    fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
        hcx.def_path_hash(*self)
    }
}

impl<CTX: HashStableContext> ToStableHashKey<CTX> for LocalDefId {
    type KeyType = DefPathHash;

    #[inline]
    fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
        hcx.def_path_hash(self.to_def_id())
    }
}

impl<CTX: HashStableContext> ToStableHashKey<CTX> for CrateNum {
    type KeyType = DefPathHash;

    #[inline]
    fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
        let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
        def_id.to_stable_hash_key(hcx)
    }
}
<commit_msg>Sprinkle inline.<commit_after>use crate::crate_disambiguator::CrateDisambiguator;
use crate::HashStableContext;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_data_structures::AtomicRef;
use rustc_index::vec::Idx;
use rustc_macros::HashStable_Generic;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::borrow::Borrow;
use std::fmt;

rustc_index::newtype_index! {
    pub struct CrateNum {
        ENCODABLE = custom
        DEBUG_FORMAT = "crate{}"
    }
}

/// Item definitions in the currently-compiled crate would have the `CrateNum`
/// `LOCAL_CRATE` in their `DefId`.
pub const LOCAL_CRATE: CrateNum = CrateNum::from_u32(0);

impl CrateNum {
    #[inline]
    pub fn new(x: usize) -> CrateNum {
        CrateNum::from_usize(x)
    }

    #[inline]
    pub fn as_def_id(&self) -> DefId {
        DefId { krate: *self, index: CRATE_DEF_INDEX }
    }
}

impl fmt::Display for CrateNum {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.private, f)
    }
}

/// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx.
/// Therefore, make sure to include the context when encode a `CrateNum`.
impl<E: Encoder> Encodable<E> for CrateNum {
    default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
        s.emit_u32(self.as_u32())
    }
}

impl<D: Decoder> Decodable<D> for CrateNum {
    default fn decode(d: &mut D) -> Result<CrateNum, D::Error> {
        Ok(CrateNum::from_u32(d.read_u32()?))
    }
}

/// A `DefPathHash` is a fixed-size representation of a `DefPath` that is
/// stable across crate and compilation session boundaries. It consists of two
/// separate 64-bit hashes. The first uniquely identifies the crate this
/// `DefPathHash` originates from (see [StableCrateId]), and the second
/// uniquely identifies the corresponding `DefPath` within that crate. Together
/// they form a unique identifier within an entire crate graph.
///
/// There is a very small chance of hash collisions, which would mean that two
/// different `DefPath`s map to the same `DefPathHash`. Proceeding compilation
/// with such a hash collision would very probably lead to an ICE, and in the
/// worst case lead to a silent mis-compilation. The compiler therefore actively
/// and exhaustively checks for such hash collisions and aborts compilation if
/// it finds one.
///
/// `DefPathHash` uses 64-bit hashes for both the crate-id part and the
/// crate-internal part, even though it is likely that there are many more
/// `LocalDefId`s in a single crate than there are individual crates in a crate
/// graph. Since we use the same number of bits in both cases, the collision
/// probability for the crate-local part will be quite a bit higher (though
/// still very small).
///
/// This imbalance is not by accident: A hash collision in the
/// crate-local part of a `DefPathHash` will be detected and reported while
/// compiling the crate in question. Such a collision does not depend on
/// outside factors and can be easily fixed by the crate maintainer (e.g. by
/// renaming the item in question or by bumping the crate version in a harmless
/// way).
///
/// A collision between crate-id hashes on the other hand is harder to fix
/// because it depends on the set of crates in the entire crate graph of a
/// compilation session. Again, using the same crate with a different version
/// number would fix the issue with a high probability -- but that might be
/// easier said then done if the crates in questions are dependencies of
/// third-party crates.
///
/// That being said, given a high quality hash function, the collision
/// probabilities in question are very small. For example, for a big crate like
/// `rustc_middle` (with ~50000 `LocalDefId`s as of the time of writing) there
/// is a probability of roughly 1 in 14,750,000,000 of a crate-internal
/// collision occurring. For a big crate graph with 1000 crates in it, there is
/// a probability of 1 in 36,890,000,000,000 of a `StableCrateId` collision.
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[derive(HashStable_Generic, Encodable, Decodable)]
pub struct DefPathHash(pub Fingerprint);

impl DefPathHash {
    /// Returns the [StableCrateId] identifying the crate this [DefPathHash]
    /// originates from.
    #[inline]
    pub fn stable_crate_id(&self) -> StableCrateId {
        StableCrateId(self.0.as_value().0)
    }

    /// Returns the crate-local part of the [DefPathHash].
    ///
    /// Used for tests.
    #[inline]
    pub fn local_hash(&self) -> u64 {
        self.0.as_value().1
    }

    /// Builds a new [DefPathHash] with the given [StableCrateId] and
    /// `local_hash`, where `local_hash` must be unique within its crate.
    pub fn new(stable_crate_id: StableCrateId, local_hash: u64) -> DefPathHash {
        DefPathHash(Fingerprint::new(stable_crate_id.0, local_hash))
    }
}

impl Borrow<Fingerprint> for DefPathHash {
    #[inline]
    fn borrow(&self) -> &Fingerprint {
        &self.0
    }
}

/// A [StableCrateId] is a 64 bit hash of `(crate-name, crate-disambiguator)`. It
/// is to [CrateNum] what [DefPathHash] is to [DefId]. It is stable across
/// compilation sessions.
///
/// Since the ID is a hash value there is a (very small) chance that two crates
/// end up with the same [StableCrateId]. The compiler will check for such
/// collisions when loading crates and abort compilation in order to avoid
/// further trouble.
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Encodable, Decodable)]
pub struct StableCrateId(u64);

impl StableCrateId {
    /// Computes the stable ID for a crate with the given name and
    /// disambiguator.
    pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> StableCrateId {
        use std::hash::Hash;

        let mut hasher = StableHasher::new();
        crate_name.hash(&mut hasher);
        crate_disambiguator.hash(&mut hasher);
        StableCrateId(hasher.finish())
    }
}

rustc_index::newtype_index! {
    /// A DefIndex is an index into the hir-map for a crate, identifying a
    /// particular definition. It should really be considered an interned
    /// shorthand for a particular DefPath.
    pub struct DefIndex {
        ENCODABLE = custom // (only encodable in metadata)

        DEBUG_FORMAT = "DefIndex({})",
        /// The crate root is always assigned index 0 by the AST Map code,
        /// thanks to `NodeCollector::new`.
        const CRATE_DEF_INDEX = 0,
    }
}

impl<E: Encoder> Encodable<E> for DefIndex {
    default fn encode(&self, _: &mut E) -> Result<(), E::Error> {
        panic!("cannot encode `DefIndex` with `{}`", std::any::type_name::<E>());
    }
}

impl<D: Decoder> Decodable<D> for DefIndex {
    default fn decode(_: &mut D) -> Result<DefIndex, D::Error> {
        panic!("cannot decode `DefIndex` with `{}`", std::any::type_name::<D>());
    }
}

/// A `DefId` identifies a particular *definition*, by combining a crate
/// index and a def index.
///
/// You can create a `DefId` from a `LocalDefId` using `local_def_id.to_def_id()`.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
pub struct DefId {
    pub krate: CrateNum,
    pub index: DefIndex,
}

impl DefId {
    /// Makes a local `DefId` from the given `DefIndex`.
    #[inline]
    pub fn local(index: DefIndex) -> DefId {
        DefId { krate: LOCAL_CRATE, index }
    }

    /// Returns whether the item is defined in the crate currently being compiled.
    #[inline]
    pub fn is_local(self) -> bool {
        self.krate == LOCAL_CRATE
    }

    #[inline]
    pub fn as_local(self) -> Option<LocalDefId> {
        if self.is_local() { Some(LocalDefId { local_def_index: self.index }) } else { None }
    }

    #[inline]
    pub fn expect_local(self) -> LocalDefId {
        self.as_local().unwrap_or_else(|| panic!("DefId::expect_local: `{:?}` isn't local", self))
    }

    pub fn is_top_level_module(self) -> bool {
        self.is_local() && self.index == CRATE_DEF_INDEX
    }
}

impl<E: Encoder> Encodable<E> for DefId {
    default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
        s.emit_struct(false, |s| {
            s.emit_struct_field("krate", true, |s| self.krate.encode(s))?;

            s.emit_struct_field("index", false, |s| self.index.encode(s))
        })
    }
}

impl<D: Decoder> Decodable<D> for DefId {
    default fn decode(d: &mut D) -> Result<DefId, D::Error> {
        d.read_struct(|d| {
            Ok(DefId {
                krate: d.read_struct_field("krate", Decodable::decode)?,
                index: d.read_struct_field("index", Decodable::decode)?,
            })
        })
    }
}

pub fn default_def_id_debug(def_id: DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    f.debug_struct("DefId").field("krate", &def_id.krate).field("index", &def_id.index).finish()
}

pub static DEF_ID_DEBUG: AtomicRef<fn(DefId, &mut fmt::Formatter<'_>) -> fmt::Result> =
    AtomicRef::new(&(default_def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));

impl fmt::Debug for DefId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        (*DEF_ID_DEBUG)(*self, f)
    }
}

rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefId);

/// A LocalDefId is equivalent to a DefId with `krate == LOCAL_CRATE`. Since
/// we encode this information in the type, we can ensure at compile time that
/// no DefIds from upstream crates get thrown into the mix. There are quite a
/// few cases where we know that only DefIds from the local crate are expected
/// and a DefId from a different crate would signify a bug somewhere. This
/// is when LocalDefId comes in handy.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LocalDefId {
    pub local_def_index: DefIndex,
}

pub const CRATE_DEF_ID: LocalDefId = LocalDefId { local_def_index: CRATE_DEF_INDEX };

impl Idx for LocalDefId {
    #[inline]
    fn new(idx: usize) -> Self {
        LocalDefId { local_def_index: Idx::new(idx) }
    }
    #[inline]
    fn index(self) -> usize {
        self.local_def_index.index()
    }
}

impl LocalDefId {
    #[inline]
    pub fn to_def_id(self) -> DefId {
        DefId { krate: LOCAL_CRATE, index: self.local_def_index }
    }

    #[inline]
    pub fn is_top_level_module(self) -> bool {
        self.local_def_index == CRATE_DEF_INDEX
    }
}

impl fmt::Debug for LocalDefId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.to_def_id().fmt(f)
    }
}

impl<E: Encoder> Encodable<E> for LocalDefId {
    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
        self.to_def_id().encode(s)
    }
}

impl<D: Decoder> Decodable<D> for LocalDefId {
    fn decode(d: &mut D) -> Result<LocalDefId, D::Error> {
        DefId::decode(d).map(|d| d.expect_local())
    }
}

rustc_data_structures::define_id_collections!(LocalDefIdMap, LocalDefIdSet, LocalDefId);

impl<CTX: HashStableContext> HashStable<CTX> for DefId {
    #[inline]
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
        self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
    }
}

impl<CTX: HashStableContext> HashStable<CTX> for LocalDefId {
    #[inline]
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
        self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
    }
}

impl<CTX: HashStableContext> HashStable<CTX> for CrateNum {
    #[inline]
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
        self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
    }
}

impl<CTX: HashStableContext> ToStableHashKey<CTX> for DefId {
    type KeyType = DefPathHash;

    #[inline]
    fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
        hcx.def_path_hash(*self)
    }
}

impl<CTX: HashStableContext> ToStableHashKey<CTX> for LocalDefId {
    type KeyType = DefPathHash;

    #[inline]
    fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
        hcx.def_path_hash(self.to_def_id())
    }
}

impl<CTX: HashStableContext> ToStableHashKey<CTX> for CrateNum {
    type KeyType = DefPathHash;

    #[inline]
    fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
        self.as_def_id().to_stable_hash_key(hcx)
    }
}
<|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/. */

//! This module contains shared types and messages for use by devtools/script.
//! The traits are here instead of in script so that the devtools crate can be
//! modified independently of the rest of Servo.

#![crate_name = "devtools_traits"]
#![crate_type = "rlib"]

#![feature(int_uint)]

#![allow(non_snake_case)]
#![allow(missing_copy_implementations)]
#![allow(unstable)]

extern crate msg;
extern crate serialize;
extern crate url;
extern crate util;

pub use self::DevtoolsControlMsg::*;
pub use self::DevtoolScriptControlMsg::*;
pub use self::EvaluateJSReply::*;

use serialize::{Decodable, Decoder};
use msg::constellation_msg::PipelineId;
use util::str::DOMString;
use url::Url;

use std::sync::mpsc::{Sender, Receiver};

pub type DevtoolsControlChan = Sender<DevtoolsControlMsg>;
pub type DevtoolsControlPort = Receiver<DevtoolScriptControlMsg>;

// Information would be attached to NewGlobal to be received and show in devtools.
// Extend these fields if we need more information.
pub struct DevtoolsPageInfo {
    pub title: DOMString,
    pub url: Url
}

/// Messages to the instruct the devtools server to update its known actors/state
/// according to changes in the browser.
pub enum DevtoolsControlMsg {
    NewGlobal(PipelineId, Sender<DevtoolScriptControlMsg>, DevtoolsPageInfo),
    SendConsoleMessage(PipelineId, ConsoleMessage),
    ServerExitMsg
}

/// Serialized JS return values
/// TODO: generalize this beyond the EvaluateJS message?
pub enum EvaluateJSReply {
    VoidValue,
    NullValue,
    BooleanValue(bool),
    NumberValue(f64),
    StringValue(String),
    ActorValue(String),
}

pub struct AttrInfo {
    pub namespace: String,
    pub name: String,
    pub value: String,
}

pub struct NodeInfo {
    pub uniqueId: String,
    pub baseURI: String,
    pub parent: String,
    pub nodeType: uint,
    pub namespaceURI: String,
    pub nodeName: String,
    pub numChildren: uint,

    pub name: String,
    pub publicId: String,
    pub systemId: String,

    pub attrs: Vec<AttrInfo>,

    pub isDocumentElement: bool,

    pub shortValue: String,
    pub incompleteValue: bool,
}

/// Messages to process in a particular script task, as instructed by a devtools client.
pub enum DevtoolScriptControlMsg {
    EvaluateJS(PipelineId, String, Sender<EvaluateJSReply>),
    GetRootNode(PipelineId, Sender<NodeInfo>),
    GetDocumentElement(PipelineId, Sender<NodeInfo>),
    GetChildren(PipelineId, String, Sender<Vec<NodeInfo>>),
    GetLayout(PipelineId, String, Sender<(f32, f32)>),
    ModifyAttribute(PipelineId, String, Vec<Modification>),
    WantsLiveNotifications(PipelineId, bool),
}

/// Messages to instruct devtools server to update its state relating to a particular
/// tab.
pub enum ScriptDevtoolControlMsg {
    /// Report a new JS error message
    ReportConsoleMsg(String),
}

#[derive(Encodable)]
pub struct Modification{
    pub attributeName: String,
    pub newValue: Option<String>,
}

impl Decodable for Modification {
    fn decode<D: Decoder>(d: &mut D) -> Result<Modification, D::Error> {
        d.read_struct("Modification", 2u, |d|
            Ok(Modification {
                attributeName: try!(d.read_struct_field("attributeName", 0u, |d| Decodable::decode(d))),
                newValue: match d.read_struct_field("newValue", 1u, |d| Decodable::decode(d)) {
                    Ok(opt) => opt,
                    Err(_) => None
                }
            })
        )
    }
}

//TODO: Include options for Warn, Debug, Info, Error messages from Console
#[derive(Clone)]
pub enum ConsoleMessage {
    LogMessage(String),
    //WarnMessage(String),
}
<commit_msg>Fix warnings in devtools_traits.<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/. */

//! This module contains shared types and messages for use by devtools/script.
//! The traits are here instead of in script so that the devtools crate can be
//! modified independently of the rest of Servo.

#![crate_name = "devtools_traits"]
#![crate_type = "rlib"]

#![feature(int_uint)]
#![feature(rustc_private)]

#![allow(non_snake_case)]
#![allow(missing_copy_implementations)]

extern crate msg;
extern crate "serialize" as rustc_serialize;
extern crate url;
extern crate util;

pub use self::DevtoolsControlMsg::*;
pub use self::DevtoolScriptControlMsg::*;
pub use self::EvaluateJSReply::*;

use rustc_serialize::{Decodable, Decoder};
use msg::constellation_msg::PipelineId;
use util::str::DOMString;
use url::Url;

use std::sync::mpsc::{Sender, Receiver};

pub type DevtoolsControlChan = Sender<DevtoolsControlMsg>;
pub type DevtoolsControlPort = Receiver<DevtoolScriptControlMsg>;

// Information would be attached to NewGlobal to be received and show in devtools.
// Extend these fields if we need more information.
pub struct DevtoolsPageInfo {
    pub title: DOMString,
    pub url: Url
}

/// Messages to the instruct the devtools server to update its known actors/state
/// according to changes in the browser.
pub enum DevtoolsControlMsg {
    NewGlobal(PipelineId, Sender<DevtoolScriptControlMsg>, DevtoolsPageInfo),
    SendConsoleMessage(PipelineId, ConsoleMessage),
    ServerExitMsg
}

/// Serialized JS return values
/// TODO: generalize this beyond the EvaluateJS message?
pub enum EvaluateJSReply {
    VoidValue,
    NullValue,
    BooleanValue(bool),
    NumberValue(f64),
    StringValue(String),
    ActorValue(String),
}

pub struct AttrInfo {
    pub namespace: String,
    pub name: String,
    pub value: String,
}

pub struct NodeInfo {
    pub uniqueId: String,
    pub baseURI: String,
    pub parent: String,
    pub nodeType: uint,
    pub namespaceURI: String,
    pub nodeName: String,
    pub numChildren: uint,

    pub name: String,
    pub publicId: String,
    pub systemId: String,

    pub attrs: Vec<AttrInfo>,

    pub isDocumentElement: bool,

    pub shortValue: String,
    pub incompleteValue: bool,
}

/// Messages to process in a particular script task, as instructed by a devtools client.
pub enum DevtoolScriptControlMsg {
    EvaluateJS(PipelineId, String, Sender<EvaluateJSReply>),
    GetRootNode(PipelineId, Sender<NodeInfo>),
    GetDocumentElement(PipelineId, Sender<NodeInfo>),
    GetChildren(PipelineId, String, Sender<Vec<NodeInfo>>),
    GetLayout(PipelineId, String, Sender<(f32, f32)>),
    ModifyAttribute(PipelineId, String, Vec<Modification>),
    WantsLiveNotifications(PipelineId, bool),
}

/// Messages to instruct devtools server to update its state relating to a particular
/// tab.
pub enum ScriptDevtoolControlMsg {
    /// Report a new JS error message
    ReportConsoleMsg(String),
}

#[derive(RustcEncodable)]
pub struct Modification{
    pub attributeName: String,
    pub newValue: Option<String>,
}

impl Decodable for Modification {
    fn decode<D: Decoder>(d: &mut D) -> Result<Modification, D::Error> {
        d.read_struct("Modification", 2u, |d|
            Ok(Modification {
                attributeName: try!(d.read_struct_field("attributeName", 0u, |d| Decodable::decode(d))),
                newValue: match d.read_struct_field("newValue", 1u, |d| Decodable::decode(d)) {
                    Ok(opt) => opt,
                    Err(_) => None
                }
            })
        )
    }
}

//TODO: Include options for Warn, Debug, Info, Error messages from Console
#[derive(Clone)]
pub enum ConsoleMessage {
    LogMessage(String),
    //WarnMessage(String),
}
<|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::FormDataBinding;
use dom::bindings::codegen::Bindings::FormDataBinding::FormDataMethods;
use dom::bindings::codegen::InheritTypes::FileCast;
use dom::bindings::codegen::UnionTypes::FileOrString::{FileOrString, eFile, eString};
use dom::bindings::error::{Fallible};
use dom::bindings::global::{GlobalRef, GlobalField};
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::blob::Blob;
use dom::file::File;
use dom::htmlformelement::HTMLFormElement;
use servo_util::str::DOMString;
use std::cell::RefCell;
use std::collections::hashmap::HashMap;

#[deriving(Clone)]
#[jstraceable]
#[must_root]
pub enum FormDatum {
    StringData(DOMString),
    FileData(JS<File>)
}

#[dom_struct]
pub struct FormData {
    data: RefCell<HashMap<DOMString, Vec<FormDatum>>>,
    reflector_: Reflector,
    global: GlobalField,
    form: Option<JS<HTMLFormElement>>
}

impl FormData {
    fn new_inherited(form: Option<JSRef<HTMLFormElement>>, global: &GlobalRef) -> FormData {
        FormData {
            data: RefCell::new(HashMap::new()),
            reflector_: Reflector::new(),
            global: GlobalField::from_rooted(global),
            form: form.map(|f| JS::from_rooted(f)),
        }
    }

    pub fn new(form: Option<JSRef<HTMLFormElement>>, global: &GlobalRef) -> Temporary<FormData> {
        reflect_dom_object(box FormData::new_inherited(form, global),
                           global, FormDataBinding::Wrap)
    }

    pub fn Constructor(global: &GlobalRef, form: Option<JSRef<HTMLFormElement>>) -> Fallible<Temporary<FormData>> {
        Ok(FormData::new(form, global))
    }
}

impl<'a> FormDataMethods for JSRef<'a, FormData> {
    #[allow(unrooted_must_root)]
    fn Append(self, name: DOMString, value: JSRef<Blob>, filename: Option<DOMString>) {
        let file = FileData(JS::from_rooted(self.get_file_from_blob(value, filename)));
        self.data.borrow_mut().insert_or_update_with(name.clone(), vec!(file.clone()),
                                        |_k, v| {v.push(file.clone());});
    }

    fn Append_(self, name: DOMString, value: DOMString) {
        self.data.borrow_mut().insert_or_update_with(name, vec!(StringData(value.clone())),
                                        |_k, v| {v.push(StringData(value.clone()));});
    }

    fn Delete(self, name: DOMString) {
        self.data.borrow_mut().remove(&name);
    }

    fn Get(self, name: DOMString) -> Option<FileOrString> {
        if self.data.borrow().contains_key_equiv(&name) {
            match (*self.data.borrow())[name][0].clone() {
                StringData(ref s) => Some(eString(s.clone())),
                FileData(ref f) => {
                    Some(eFile(f.clone()))
                }
            }
        } else {
            None
        }
    }

    fn Has(self, name: DOMString) -> bool {
        self.data.borrow().contains_key_equiv(&name)
    }
    #[allow(unrooted_must_root)]
    fn Set(self, name: DOMString, value: JSRef<Blob>, filename: Option<DOMString>) {
        let file = FileData(JS::from_rooted(self.get_file_from_blob(value, filename)));
        self.data.borrow_mut().insert(name, vec!(file));
    }

    fn Set_(self, name: DOMString, value: DOMString) {
        self.data.borrow_mut().insert(name, vec!(StringData(value)));
    }
}

impl Reflectable for FormData {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }
}

trait PrivateFormDataHelpers{
  fn get_file_from_blob(&self, value: JSRef<Blob>, filename: Option<DOMString>) -> Temporary<File>;
}

impl PrivateFormDataHelpers for FormData {
    fn get_file_from_blob(&self, value: JSRef<Blob>, filename: Option<DOMString>) -> Temporary<File> {
        let global = self.global.root();
        let f: Option<JSRef<File>> = FileCast::to_ref(value);
        let name = filename.unwrap_or(f.map(|inner| inner.name().clone()).unwrap_or("blob".to_string()));
        File::new(&global.root_ref(), value, name)
    }
}
<commit_msg>Use DOMRefCell for FormData.<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::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::FormDataBinding;
use dom::bindings::codegen::Bindings::FormDataBinding::FormDataMethods;
use dom::bindings::codegen::InheritTypes::FileCast;
use dom::bindings::codegen::UnionTypes::FileOrString::{FileOrString, eFile, eString};
use dom::bindings::error::{Fallible};
use dom::bindings::global::{GlobalRef, GlobalField};
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::blob::Blob;
use dom::file::File;
use dom::htmlformelement::HTMLFormElement;
use servo_util::str::DOMString;
use std::collections::hashmap::HashMap;

#[deriving(Clone)]
#[jstraceable]
#[must_root]
pub enum FormDatum {
    StringData(DOMString),
    FileData(JS<File>)
}

#[dom_struct]
pub struct FormData {
    data: DOMRefCell<HashMap<DOMString, Vec<FormDatum>>>,
    reflector_: Reflector,
    global: GlobalField,
    form: Option<JS<HTMLFormElement>>
}

impl FormData {
    fn new_inherited(form: Option<JSRef<HTMLFormElement>>, global: &GlobalRef) -> FormData {
        FormData {
            data: DOMRefCell::new(HashMap::new()),
            reflector_: Reflector::new(),
            global: GlobalField::from_rooted(global),
            form: form.map(|f| JS::from_rooted(f)),
        }
    }

    pub fn new(form: Option<JSRef<HTMLFormElement>>, global: &GlobalRef) -> Temporary<FormData> {
        reflect_dom_object(box FormData::new_inherited(form, global),
                           global, FormDataBinding::Wrap)
    }

    pub fn Constructor(global: &GlobalRef, form: Option<JSRef<HTMLFormElement>>) -> Fallible<Temporary<FormData>> {
        Ok(FormData::new(form, global))
    }
}

impl<'a> FormDataMethods for JSRef<'a, FormData> {
    #[allow(unrooted_must_root)]
    fn Append(self, name: DOMString, value: JSRef<Blob>, filename: Option<DOMString>) {
        let file = FileData(JS::from_rooted(self.get_file_from_blob(value, filename)));
        self.data.borrow_mut().insert_or_update_with(name.clone(), vec!(file.clone()),
                                        |_k, v| {v.push(file.clone());});
    }

    fn Append_(self, name: DOMString, value: DOMString) {
        self.data.borrow_mut().insert_or_update_with(name, vec!(StringData(value.clone())),
                                        |_k, v| {v.push(StringData(value.clone()));});
    }

    fn Delete(self, name: DOMString) {
        self.data.borrow_mut().remove(&name);
    }

    fn Get(self, name: DOMString) -> Option<FileOrString> {
        if self.data.borrow().contains_key_equiv(&name) {
            match (*self.data.borrow())[name][0].clone() {
                StringData(ref s) => Some(eString(s.clone())),
                FileData(ref f) => {
                    Some(eFile(f.clone()))
                }
            }
        } else {
            None
        }
    }

    fn Has(self, name: DOMString) -> bool {
        self.data.borrow().contains_key_equiv(&name)
    }
    #[allow(unrooted_must_root)]
    fn Set(self, name: DOMString, value: JSRef<Blob>, filename: Option<DOMString>) {
        let file = FileData(JS::from_rooted(self.get_file_from_blob(value, filename)));
        self.data.borrow_mut().insert(name, vec!(file));
    }

    fn Set_(self, name: DOMString, value: DOMString) {
        self.data.borrow_mut().insert(name, vec!(StringData(value)));
    }
}

impl Reflectable for FormData {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }
}

trait PrivateFormDataHelpers{
  fn get_file_from_blob(&self, value: JSRef<Blob>, filename: Option<DOMString>) -> Temporary<File>;
}

impl PrivateFormDataHelpers for FormData {
    fn get_file_from_blob(&self, value: JSRef<Blob>, filename: Option<DOMString>) -> Temporary<File> {
        let global = self.global.root();
        let f: Option<JSRef<File>> = FileCast::to_ref(value);
        let name = filename.unwrap_or(f.map(|inner| inner.name().clone()).unwrap_or("blob".to_string()));
        File::new(&global.root_ref(), value, name)
    }
}
<|endoftext|>