<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::mem::{size_of, transmute_copy};
use std::cmp;
use std::ptr::copy_nonoverlapping;

macro_rules! read_num_bytes {
  ($ty:ty, $size:expr, $src:expr, $which:ident) => ({
    assert!($size <= $src.len());
    let mut data: $ty = 0;
    unsafe {
      copy_nonoverlapping(
        $src.as_ptr(),
        &mut data as *mut $ty as *mut u8,
        $size);
    }
    data.$which()
  });
}

#[inline]
fn trailing_bits(v: u64, num_bits: usize) -> u64 {
  if num_bits == 0 {
    return 0;
  }
  if num_bits >= 64 {
    return v;
  }
  let n = 64 - num_bits;
  (v << n) >> n
}

pub struct BitReader<'a> {
  /// The buffer to read from, passed in by client
  buffer: &'a [u8],

  /// Bytes are memcpy'd from buffer_ and values are read from this variable. This is
  /// faster than reading values byte by byte directly from buffer_.
  buffered_values: u64,

  /// Byte offset in `buffer`
  byte_offset: usize,

  /// Bit offset in `buffered_values`
  bit_offset: usize,

  /// Total number of bytes in `buffer`
  total_bytes: usize
}

impl<'a> BitReader<'a> {
  pub fn new(buffer: &'a mut [u8]) -> Self {
    let total_bytes = buffer.len();
    let num_bytes = cmp::min(8, total_bytes);
    let buffered_values = read_num_bytes!(u64, num_bytes, buffer, to_le);
    BitReader {
      buffer: buffer, buffered_values: buffered_values,
      byte_offset: 0, bit_offset: 0, total_bytes: total_bytes
    }
  }

  #[inline]
  pub fn reset(&mut self, buffer: &'a [u8]) {
    self.buffer = buffer;
    self.byte_offset = 0;
    self.bit_offset = 0;
  }

  #[inline]
  pub fn get_value<T>(&mut self, num_bits: usize) -> Option<T> {
    assert!(num_bits <= 32);
    assert!(num_bits <= size_of::<T>() * 8);

    if self.byte_offset * 8 + self.bit_offset + num_bits > self.total_bytes * 8 {
      return None;
    }

    let mut v = trailing_bits(self.buffered_values, self.bit_offset + num_bits) >> self.bit_offset;
    self.bit_offset += num_bits;

    if self.bit_offset >= 64 {
      self.byte_offset += 8;
      self.bit_offset -= 64;

      let bytes_to_read = cmp::min(self.total_bytes - self.byte_offset, 8);
      self.buffered_values = read_num_bytes!(
        u64, bytes_to_read, self.buffer[self.byte_offset..], to_le);

      v |= trailing_bits(self.buffered_values, self.bit_offset) << (num_bits - self.bit_offset);
    }

    let result: T = unsafe {
      transmute_copy::<u64, T>(&v)
    };
    Some(result)
  }
}

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

  #[test]
  fn test_bit_reader() {
    let mut buffer = vec![255, 0];
    let mut bit_reader = BitReader::new(buffer.as_mut_slice());
    let v1 = bit_reader.get_value::<i32>(1);
    assert!(v1.is_some());
    assert_eq!(v1.unwrap(), 1);
    let v2 = bit_reader.get_value::<i32>(2);
    assert!(v2.is_some());
    assert_eq!(v2.unwrap(), 3);
    let v3 = bit_reader.get_value::<i32>(3);
    assert!(v3.is_some());
    assert_eq!(v3.unwrap(), 7);
    let v4 = bit_reader.get_value::<i32>(4);
    assert!(v4.is_some());
    assert_eq!(v4.unwrap(), 3);
  }
}
<commit_msg>Add more tests and more docs for bit_util<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::mem::{size_of, transmute_copy};
use std::cmp;
use std::ptr::copy_nonoverlapping;

/// Read `$size` of bytes from `$src`, and reinterpret them
/// as type `$ty`. `$which` is used to specify endianness.
/// This is copied and modified from byteoder crate.
macro_rules! read_num_bytes {
  ($ty:ty, $size:expr, $src:expr, $which:ident) => ({
    assert!($size <= $src.len());
    let mut data: $ty = 0;
    unsafe {
      copy_nonoverlapping(
        $src.as_ptr(),
        &mut data as *mut $ty as *mut u8,
        $size);
    }
    data.$which()
  });
}

/// Returns the `num_bits` least-significant bits of `v`
#[inline]
fn trailing_bits(v: u64, num_bits: usize) -> u64 {
  if num_bits == 0 {
    return 0;
  }
  if num_bits >= 64 {
    return v;
  }
  let n = 64 - num_bits;
  (v << n) >> n
}

pub struct BitReader<'a> {
  /// The byte buffer to read from, passed in by client
  buffer: &'a [u8],

  /// Bytes are memcpy'd from `buffer` and values are read from this variable.
  /// This is faster than reading values byte by byte directly from `buffer`
  buffered_values: u64,

  /// Current byte offset in `buffer`
  byte_offset: usize,

  /// Current bit offset in `buffered_values`
  bit_offset: usize,

  /// Total number of bytes in `buffer`
  total_bytes: usize
}

impl<'a> BitReader<'a> {
  pub fn new(buffer: &'a mut [u8]) -> Self {
    let total_bytes = buffer.len();
    let num_bytes = cmp::min(8, total_bytes);
    let buffered_values = read_num_bytes!(u64, num_bytes, buffer, to_le);
    BitReader {
      buffer: buffer, buffered_values: buffered_values,
      byte_offset: 0, bit_offset: 0, total_bytes: total_bytes
    }
  }

  #[inline]
  pub fn reset(&mut self, buffer: &'a [u8]) {
    self.buffer = buffer;
    self.byte_offset = 0;
    self.bit_offset = 0;
  }

  #[inline]
  pub fn get_value<T>(&mut self, num_bits: usize) -> Option<T> {
    assert!(num_bits <= 32);
    assert!(num_bits <= size_of::<T>() * 8);

    if self.byte_offset * 8 + self.bit_offset + num_bits > self.total_bytes * 8 {
      return None;
    }

    let mut v = trailing_bits(self.buffered_values, self.bit_offset + num_bits) >> self.bit_offset;
    self.bit_offset += num_bits;

    if self.bit_offset >= 64 {
      self.byte_offset += 8;
      self.bit_offset -= 64;

      let bytes_to_read = cmp::min(self.total_bytes - self.byte_offset, 8);
      self.buffered_values = read_num_bytes!(
        u64, bytes_to_read, self.buffer[self.byte_offset..], to_le);

      v |= trailing_bits(self.buffered_values, self.bit_offset) << (num_bits - self.bit_offset);
    }

    // TODO: better to avoid copying here
    let result: T = unsafe {
      transmute_copy::<u64, T>(&v)
    };
    Some(result)
  }
}

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

  #[test]
  fn test_bit_reader() {
    let mut buffer = vec![255, 0];
    let mut bit_reader = BitReader::new(buffer.as_mut_slice());
    let v1 = bit_reader.get_value::<i32>(1);
    assert!(v1.is_some());
    assert_eq!(v1.unwrap(), 1);
    let v2 = bit_reader.get_value::<i32>(2);
    assert!(v2.is_some());
    assert_eq!(v2.unwrap(), 3);
    let v3 = bit_reader.get_value::<i32>(3);
    assert!(v3.is_some());
    assert_eq!(v3.unwrap(), 7);
    let v4 = bit_reader.get_value::<i32>(4);
    assert!(v4.is_some());
    assert_eq!(v4.unwrap(), 3);
  }

  #[test]
  fn test_bit_reader_boundary() {
    let mut buffer = vec![10, 0, 0, 0, 20, 0, 30, 0, 0, 0, 40, 0];
    let mut bit_reader = BitReader::new(buffer.as_mut_slice());
    let v1 = bit_reader.get_value::<i64>(32);
    assert!(v1.is_some());
    assert_eq!(v1.unwrap(), 10);
    let v2 = bit_reader.get_value::<i16>(16);
    assert!(v2.is_some());
    assert_eq!(v2.unwrap(), 20);
    let v3 = bit_reader.get_value::<i32>(32);
    assert!(v3.is_some());
    assert_eq!(v3.unwrap(), 30);
    let v4 = bit_reader.get_value::<i32>(16);
    assert!(v4.is_some());
    assert_eq!(v4.unwrap(), 40);
  }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use super::context::Context;
use super::vertex_data::{VertexData, VertexBytes, VertexAttribBinder};
use super::buffer::{Buffer, BufferBinding, ArrayBufferBinding};

pub struct VertexBuffer<T: VertexData> {
    pub attrib_binder: Option<T::Binder>,
    pub buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: VertexData> VertexBuffer<T> {
    pub fn new(buffer: Buffer) -> Self {
        VertexBuffer {
            attrib_binder: None,
            buffer: buffer,
            count: 0,
            phantom: PhantomData
        }
    }

    pub fn build_attrib_binder(&self)
        -> <T::Binder as VertexAttribBinder>::Builder
    {
        T::build_attrib_binder()
    }

    pub fn bind(&self, gl: &super::Context) -> Result<(), ()> {
        match self.attrib_binder {
            Some(ref binder) => {
                binder.bind(gl);
                Ok(())
            },
            None => { Err(()) }
        }
    }
}

pub struct VertexBufferBinding<'a, T: VertexData>
    where T: 'a, T::Binder: 'a
{
    gl_buffer: ArrayBufferBinding<'a>,
    vbo: &'a mut VertexBuffer<T>
}

impl<'a, T: VertexData> VertexBufferBinding<'a, T>
    where T: 'a, T::Binder: 'a
{
    pub fn new(gl_buffer: ArrayBufferBinding<'a>, vbo: &'a mut VertexBuffer<T>)
        -> Self
    {
        VertexBufferBinding {
            gl_buffer: gl_buffer,
            vbo: vbo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: VertexBytes
    {
        self.vbo.count = data.len();
        self.gl_buffer.buffer_bytes(data.vertex_bytes(), usage);
    }
}

#[macro_export]
macro_rules! bind_vertex_buffer {
    ($gl:expr, $vbo:expr) => {
        {
            let vbo = $vbo;
            let gl : &mut _ = $gl;

            {
                vbo.bind(gl).unwrap();
            }

            let gl_buffer = bind_array_buffer!(gl, &mut vbo.buffer);
            $crate::VertexBufferBinding::new(gl_buffer, vbo)
        }
    }
}
<commit_msg>Replace `VertexBuffer::new` with `Context.new_vertex_buffer`<commit_after>use std::marker::PhantomData;
use super::context::Context;
use super::vertex_data::{VertexData, VertexBytes, VertexAttribBinder};
use super::buffer::{Buffer, BufferBinding, ArrayBufferBinding};

pub struct VertexBuffer<T: VertexData> {
    pub attrib_binder: Option<T::Binder>,
    pub buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: VertexData> VertexBuffer<T> {
    pub fn build_attrib_binder(&self)
        -> <T::Binder as VertexAttribBinder>::Builder
    {
        T::build_attrib_binder()
    }

    pub fn bind(&self, gl: &super::Context) -> Result<(), ()> {
        match self.attrib_binder {
            Some(ref binder) => {
                binder.bind(gl);
                Ok(())
            },
            None => { Err(()) }
        }
    }
}

impl Context {
    pub fn new_vertex_buffer<T: VertexData>(&self) -> VertexBuffer<T> {
        VertexBuffer {
            attrib_binder: None,
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

pub struct VertexBufferBinding<'a, T: VertexData>
    where T: 'a, T::Binder: 'a
{
    gl_buffer: ArrayBufferBinding<'a>,
    vbo: &'a mut VertexBuffer<T>
}

impl<'a, T: VertexData> VertexBufferBinding<'a, T>
    where T: 'a, T::Binder: 'a
{
    pub fn new(gl_buffer: ArrayBufferBinding<'a>, vbo: &'a mut VertexBuffer<T>)
        -> Self
    {
        VertexBufferBinding {
            gl_buffer: gl_buffer,
            vbo: vbo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: VertexBytes
    {
        self.vbo.count = data.len();
        self.gl_buffer.buffer_bytes(data.vertex_bytes(), usage);
    }
}

#[macro_export]
macro_rules! bind_vertex_buffer {
    ($gl:expr, $vbo:expr) => {
        {
            let vbo = $vbo;
            let gl : &mut _ = $gl;

            {
                vbo.bind(gl).unwrap();
            }

            let gl_buffer = bind_array_buffer!(gl, &mut vbo.buffer);
            $crate::VertexBufferBinding::new(gl_buffer, vbo)
        }
    }
}
<|endoftext|>


<commit_before>use core::intrinsics::transmute;

pub unsafe trait VSpaceWindow<'a> {
    fn base(&self) -> usize;
    fn size(&self) -> usize;
    unsafe fn make<T>(&self) -> &'a T {
        unimplemented!()
    }
    /* Passing in a window to describe the window you want to create
     * is a little backwards, but it provides the nicest API as far
     * as I can tell */
    unsafe fn subwindow<'i, I, O: ?Sized>(&self, window: I) -> &'a O where O: VSpaceWindow<'a> + Default, I: VSpaceWindow<'i> {
        /* Validate the range for this window */
        if !self.range_valid(window.base(), window.size()) {
            panic!("Cannot construct window with range {} {}, from {} {}");
        }
        /* transmate to extend the lifetime. This is safe as
         * it is a zero sized object */
        transmute(&O::default())
    }
    fn range_valid(&self, b: usize, s: usize) -> bool {
        /* We have moved the `- s` to the other side of the equation
         * so that if `self.base() + self.size()` overflowed
         * then subtracting `s` will either correct if the range is
         * valid, or not correct in which case the range is invalid
         * and the comparison will fail */
        b >= self.base() && b <= self.base() + self.size() - s
    }
}
<commit_msg>Allow over/underflow to happen in vspace range checking<commit_after>use core::intrinsics::transmute;
use core::num::Wrapping;

pub unsafe trait VSpaceWindow<'a> {
    fn base(&self) -> usize;
    fn size(&self) -> usize;
    unsafe fn make<T>(&self) -> &'a T {
        unimplemented!()
    }
    /* Passing in a window to describe the window you want to create
     * is a little backwards, but it provides the nicest API as far
     * as I can tell */
    unsafe fn subwindow<'i, I, O: ?Sized>(&self, window: I) -> &'a O where O: VSpaceWindow<'a> + Default, I: VSpaceWindow<'i> {
        /* Validate the range for this window */
        if !self.range_valid(window.base(), window.size()) {
            panic!("Cannot construct window with range {} {}, from {} {}");
        }
        /* transmate to extend the lifetime. This is safe as
         * it is a zero sized object */
        transmute(&O::default())
    }
    fn range_valid(&self, b: usize, s: usize) -> bool {
        /* We have moved the `- s` to the other side of the equation
         * so that if `self.base() + self.size()` overflowed
         * then subtracting `s` will either correct if the range is
         * valid, or not correct in which case the range is invalid
         * and the comparison will fail */
        b >= self.base() && b <= (Wrapping(self.base()) + Wrapping(self.size()) - Wrapping(s)).0
    }
}
<|endoftext|>


<commit_before>use rosxmlrpc;
use rustc_serialize::{Decodable, Encodable};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use super::error::ServerError as Error;
use super::slavehandler::{add_publishers_to_subscription, SlaveHandler};
use tcpros::{self, Message, Publisher, PublisherStream, Subscriber};

pub struct Slave {
    name: String,
    server: rosxmlrpc::Server,
    publications: Arc<Mutex<HashMap<String, Publisher>>>,
    subscriptions: Arc<Mutex<HashMap<String, Subscriber>>>,
}

type SerdeResult<T> = Result<T, Error>;

impl Slave {
    pub fn new(master_uri: &str, server_uri: &str, name: &str) -> Result<Slave, Error> {
        let handler = SlaveHandler::new(master_uri, name);
        let pubs = handler.publications.clone();
        let subs = handler.subscriptions.clone();
        let server = rosxmlrpc::Server::new(server_uri, SlaveHandler::new(master_uri, name))?;
        Ok(Slave {
            name: String::from(name),
            server: server,
            publications: pubs,
            subscriptions: subs,
        })
    }

    pub fn uri(&self) -> &str {
        return &self.server.uri;
    }

    pub fn add_publishers_to_subscription<T>(&mut self,
                                             topic: &str,
                                             publishers: T)
                                             -> SerdeResult<()>
        where T: Iterator<Item = String>
    {
        add_publishers_to_subscription(&mut self.subscriptions.lock().unwrap(),
                                       &self.name,
                                       topic,
                                       publishers)
    }

    pub fn add_publication<T>(&mut self,
                              hostname: &str,
                              topic: &str)
                              -> Result<PublisherStream<T>, tcpros::Error>
        where T: Message + Encodable
    {
        use std::collections::hash_map::Entry;
        match self.publications.lock().unwrap().entry(String::from(topic)) {
            Entry::Occupied(publisher_entry) => publisher_entry.get().stream(),
            Entry::Vacant(entry) => {
                let publisher = Publisher::new::<T, _>(format!("{}:0", hostname).as_str(), topic)?;
                entry.insert(publisher).stream()
            }
        }
    }

    pub fn remove_publication(&mut self, topic: &str) {
        self.publications.lock().unwrap().remove(topic);
    }

    pub fn add_subscription<T, F>(&mut self, topic: &str, callback: F) -> Result<(), Error>
        where T: Message + Decodable,
              F: Fn(T) -> () + Send + 'static
    {
        use std::collections::hash_map::Entry;
        match self.subscriptions.lock().unwrap().entry(String::from(topic)) {
            Entry::Occupied(..) => {
                error!("Duplicate subscription to topic '{}' attempted", topic);
                Err(Error::Critical(String::from("Could not add duplicate subscription to topic")))
            }
            Entry::Vacant(entry) => {
                let subscriber = Subscriber::new::<T, F>(&self.name, topic, callback);
                entry.insert(subscriber);
                Ok(())
            }
        }
    }

    pub fn remove_subscription(&mut self, topic: &str) {
        self.subscriptions.lock().unwrap().remove(topic);
    }
}
<commit_msg>Fix unused handler<commit_after>use rosxmlrpc;
use rustc_serialize::{Decodable, Encodable};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use super::error::ServerError as Error;
use super::slavehandler::{add_publishers_to_subscription, SlaveHandler};
use tcpros::{self, Message, Publisher, PublisherStream, Subscriber};

pub struct Slave {
    name: String,
    server: rosxmlrpc::Server,
    publications: Arc<Mutex<HashMap<String, Publisher>>>,
    subscriptions: Arc<Mutex<HashMap<String, Subscriber>>>,
}

type SerdeResult<T> = Result<T, Error>;

impl Slave {
    pub fn new(master_uri: &str, server_uri: &str, name: &str) -> Result<Slave, Error> {
        let handler = SlaveHandler::new(master_uri, name);
        let pubs = handler.publications.clone();
        let subs = handler.subscriptions.clone();
        let server = rosxmlrpc::Server::new(server_uri, handler)?;
        Ok(Slave {
            name: String::from(name),
            server: server,
            publications: pubs,
            subscriptions: subs,
        })
    }

    pub fn uri(&self) -> &str {
        return &self.server.uri;
    }

    pub fn add_publishers_to_subscription<T>(&mut self,
                                             topic: &str,
                                             publishers: T)
                                             -> SerdeResult<()>
        where T: Iterator<Item = String>
    {
        add_publishers_to_subscription(&mut self.subscriptions.lock().unwrap(),
                                       &self.name,
                                       topic,
                                       publishers)
    }

    pub fn add_publication<T>(&mut self,
                              hostname: &str,
                              topic: &str)
                              -> Result<PublisherStream<T>, tcpros::Error>
        where T: Message + Encodable
    {
        use std::collections::hash_map::Entry;
        match self.publications.lock().unwrap().entry(String::from(topic)) {
            Entry::Occupied(publisher_entry) => publisher_entry.get().stream(),
            Entry::Vacant(entry) => {
                let publisher = Publisher::new::<T, _>(format!("{}:0", hostname).as_str(), topic)?;
                entry.insert(publisher).stream()
            }
        }
    }

    pub fn remove_publication(&mut self, topic: &str) {
        self.publications.lock().unwrap().remove(topic);
    }

    pub fn add_subscription<T, F>(&mut self, topic: &str, callback: F) -> Result<(), Error>
        where T: Message + Decodable,
              F: Fn(T) -> () + Send + 'static
    {
        use std::collections::hash_map::Entry;
        match self.subscriptions.lock().unwrap().entry(String::from(topic)) {
            Entry::Occupied(..) => {
                error!("Duplicate subscription to topic '{}' attempted", topic);
                Err(Error::Critical(String::from("Could not add duplicate subscription to topic")))
            }
            Entry::Vacant(entry) => {
                let subscriber = Subscriber::new::<T, F>(&self.name, topic, callback);
                entry.insert(subscriber);
                Ok(())
            }
        }
    }

    pub fn remove_subscription(&mut self, topic: &str) {
        self.subscriptions.lock().unwrap().remove(topic);
    }
}
<|endoftext|>


<commit_before>/// Implements the block_add procedure

/*

Block storing is a tricky part; blocks are stored in the spent-tree and referenced in the
 hash-index

 This can go out of order:  For instance consider 5 blocks added in the order A, B, D, E, C
 (for this pseudocode, each block has the previous letter as prev_block_hash)

 We show the some pseudocode for actions on hashindex (hi) and spent-tree (st),
 for the insertion of this sequence

 insert A:
    st.store_block(A)
    fn do_connect(null,A) =
      (prev = null, no get_or_set)
      hi.set(A)

 insert B:
    st.store_block(B)
    hi.get_or_set(A, guard[B]) returns A
    fn do_connect(A,B) =
      st.connect_block(A,B)
      hi.set(B)

 insert D:
    st.store_block(D)
    hi.get_or_set(C, guard[D]) return none & adds guard[D] at hash C

 insert E:
   st.store_block(E)
   hi.get_or_set(D, guard[E]) return none & adds guard[E] at hash D

 insert C:
   st.store_block(C)
   hi.get_or_set(B, guard[C]) returns B
   fn do_connect(B,C) =
      st.connect_block(B,C)
      hi.set(C) -> fail due to guard([D])

        loop {
            hi.get(C) -> return guard[D]
            do_connect(C,D)
            hi.set(C, guard([D]) -> fail or break
        }

  Now let us consider what happens when C' is inserted *during* processing of B. Copyied from B above:
  B:
    st.store_block(B)
    hi.get_or_set(A, guard[B]) returns A
    fn do_connect(A,B) =
      st.connect_block(A,B)
        < here C' is inserted as B -> guard[C']
      hi.set(B) -> fail due to guard[C']
      loop {
            hi.get(B) -> return guard[C']
            do_connect(B,C')
            hi.set(B, guard([C']) -> success!
        }

*/

use hash::*;
use util::*;
use buffer::*;
use rayon::prelude::*;
use slog ;

use store::Store;
use transaction;
use merkle_tree;
use block::*;
use store::Record;
use store::BlockPtr;
use store::HashIndexGuard;

type BlockResult<T> = Result<T, BlockError>;

/// Returns true if the given hash is the hash of a genesis block
fn is_genesis_block(hash: Hash32) -> bool {
    const HASH_GENESIS: &'static str =
        "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";

    let genesis = Hash32Buf::from_slice(&from_hex_rev(HASH_GENESIS));

    genesis.as_ref() == hash
}

// Connects two blocks (A,B) in the spent-tree and then stores the hash of B in the hash-index
// Connecting the blocks will verify double-spents
//
// It can be that another block C is also waiting for B; this will trigger their connection (B,C) too
// and maybe (C,D)... etcetera
//
// This would be neat to do recursively, but this could exhaust the stack , we use a loop with
// a to_do for connections.
fn connect_block(
    store:           &mut Store,
    this_block_hash: Hash32,
    previous_block:  Option<BlockPtr>,
    this_block:      BlockPtr)

    -> BlockResult<()>
{
    trace!(store.logger, "Connect block";
        "this_hash"  =>  format!("{:?}", this_block_hash),
        "prev_end"   =>  format!("{:?}", previous_block),
        "this_start" =>  format!("{:?}", this_block)
    );

    // we lay connections between the end of one block and the start of this_block
    // prev_end is None only for genesis
    #[derive(Debug)]
    struct Connection {
        block:         BlockPtr,
        block_hash:    Hash32Buf,
        solved_guards: Vec<BlockPtr>
    }

    // connect first block ...
    if let Some(previous_block) = previous_block {
        store.spent_tree.connect_block( &mut store.spent_index, & store.logger, previous_block, this_block) ?;
    }

    // The to_do list contains blocks that are connected to their previous but not yet added to the
    // block-index.
    let mut todo = vec![Connection {
        block:         this_block,
        block_hash:    this_block_hash.as_buf(),
        solved_guards: vec![]
    }];

    while let Some(conn) = todo.pop() {

        trace!(store.logger, "Connect block - set-hash-loop";
            "conn"  => format!("{:?}",   conn));

        // if we can store this hash we can move to the next one
        if store.block_index.set(conn.block_hash.as_ref(), conn.block.to_non_guard(), &conn.solved_guards) {
            trace!(store.logger, "Connect block - set-hash-loop - ok");
            continue;
        }

        let guards = store.block_index.get(conn.block_hash.as_ref());

        if guards.iter().any(|ptr| !ptr.is_guard()) {
            // this is not a guard, this is _this_ block. It seems the block
            // was added by a concurrent user; will do fine.
            trace!(store.logger, "Connect block - set-hash-loop - concurrent add");
            continue;
        }

        //let guards = store.hash_index.get(conn.this_hash);
        todo.push(Connection {
            block: conn.block,
            block_hash: conn.block_hash,
            solved_guards: guards.clone()
        });

        //let guards = store.hash_index.get(conn.this_hash.as_buf());

        for ptr in guards {
            if conn.solved_guards.contains(&ptr) {
                continue;
            }

            let hash = store.get_block_hash(ptr);

            trace!(store.logger, "Connect block - set-hash-loop";
                "guard" => format!("{:?}", ptr),
                "hash" => format!("{:?}",   hash),
                "conn"  => format!("{:?}",   conn));

            store.spent_tree.revolve_orphan_pointers(
                &mut store.transactions,
                &mut store.tx_index,
                ptr
            );

            store.spent_tree.connect_block(&mut store.spent_index, &store.logger, conn.block, ptr)?;

            todo.push(Connection {
                block: ptr,
                block_hash: hash,
                solved_guards: vec![]

            });

        }
    }

    Ok(())
}

/// Returns true if the block is already stored
fn block_exists(store: & mut Store, block_hash: Hash32) -> bool {
    let ptr = store.block_index.get(block_hash);

    ptr.iter().any( | ptr | !ptr.is_guard())

}

/// Verifies and stores the transactions in the block.
/// Also verifies the merkle_root & the amounts
///
/// Returns a list fileptrs to the transactions
///
fn verify_and_store_transactions(store: &mut Store, block: &Block) -> BlockResult<Vec<Record>> {

    if block.to_raw().len() > ::block::MAX_BLOCK_SIZE {
        panic!("Block too large");
        return Err(BlockError::BlockTooLarge);
    }

    // we map the transactions to a tuple of hash and a record
    let tuples: Vec<(Hash32Buf, Record)> = block.txs.iter().map(|tx| {

        let tx_store = &mut store.transactions.clone();
        let tx_index = &mut store.tx_index.clone();

        let hash_buf = Hash32Buf::double_sha256(tx.to_raw());

        let res = tx.verify_and_store(tx_index, tx_store, hash_buf.as_ref()).unwrap();

        // AlreadyExists and VerifiedAndStored are both ok here
        let ptr = match res {
            transaction::TransactionOk::AlreadyExists(ptr) => ptr,
            transaction::TransactionOk::VerifiedAndStored(ptr) => ptr
        };

        let rec = Record::new_transaction(ptr);

        (hash_buf, rec)
    }).collect();

    // the result of above loop is a hash and a ptr for each transaction; split them.
    let (hashes, ptrs): (Vec<Hash32Buf>, Vec<Record>) = tuples.into_iter().unzip();

    // check merkle roots
    let calculated_merkle_root = merkle_tree::get_merkle_root(hashes);
    block.verify_merkle_root(calculated_merkle_root.as_ref()).unwrap();

    // construct records for in the spent-tree
    let mut records: Vec<Record> = Vec::new();
    for (tx,rec) in block.txs.iter().zip(ptrs) {
        records.push(rec);
        records.append(&mut tx.get_output_records(store));
    }

    Ok(records)
}

/// Validates and stores a block;
///
pub fn add_block(store: &mut Store, buffer: &[u8]) {

    // parse
    let block      = Block::new(buffer) .unwrap();
    let block_hash = Hash32Buf::double_sha256( block.header.to_raw());

    let block_logger = slog::Logger::new(&store.logger, o!());
    info!(block_logger, "add_block - start"; "hash" => format!("{:?}", block_hash));

    // already done?
    if block_exists(store, block_hash.as_ref()) {
        info!(store.logger, "add_block - Block already exists");
        return;
    }

    // check and store the transactions in block_content and check the merkle_root
    let spent_tree_ptrs = verify_and_store_transactions(store, &block).unwrap();

    // store the blockheader in block_content
    let block_header_ptr = store.block_headers.write( &block.header.to_raw());

    // we also store the txcount, although we only use it for a reindex benchmark
    let _ = store.block_headers.write_fixed( &block.txs.len());

    // store the block in the spent_tree
    /*
    let block_ptr       = store.spent_tree.store_block(block_header_ptr, spent_tree_ptrs);

    if is_genesis_block(block_hash.as_ref()) {

        info ! (block_logger, "add_block - storing genesis block");

        // there is None previous block, but we call connect_block anyway as this will also
        // connect to next blocks if they are already in
        connect_block(store, block_hash.as_ref(), None, block_ptr).unwrap();
    }
    else {

        // we retrieve the pointer to the end of the previous block from the hash-index
        // if it is not yet in, this hash will be inserted as a guard-block
        let previous_block = store.block_index.get_or_set( block.header.prev_hash, block_ptr.to_guard());

        info! (block_logger, "add_block - tranactions done";
            "previous" => format!("{:?}", block.header.prev_hash),
            "ptr" => format!("{:?}", previous_block));

        // if it is in, we will connect
        if let Some(previous_block) = previous_block {

            connect_block(store, block_hash.as_ref(), Some(previous_block), block_ptr).unwrap();
        }

    }
*/
    // TODO verify amounts
    // TODO verify PoW
    // TODO verify header-syntax

    info!(block_logger, "add_block - done");
}

#[cfg(test)]
mod tests {

    use store;
    use super::*;

    use rayon::prelude::*;
    #[test]
    fn test_clone_into_thread() {

        struct X { data: Vec<u32> };
        impl Clone for X {
            fn clone(&self) -> X { X { data: self.data.clone() } }
        }
        let mut x = X { data: vec![1,2,3,4,5,6,7,8,9,10]};

        let y = vec![10,11,12,13,14,15,16,17,18,19,20];

        y.into_par_iter().map(|z| {
            let u = &mut x.clone(); // is this possible?
            println!("{:?} {:?} ", z, u.data); u.data.push(2);
        });
    }

    #[test]
    fn test_block_simple() {

        let mut store = store::Store::new(& test_cfg!());

        tx_builder!(bld);

        let block0 = genesis!();

        let block1 = blk!(prev = block0;
            tx!(bld; coinbase => b;11 ),
            tx!(bld; b => c,e )
        );

        let block2 = blk!(prev = block1;
            tx!(bld; coinbase => f;12 ),
            tx!(bld; c => g )
        );

        add_block(&mut store, &block0);
        add_block(&mut store, &block1);
        add_block(&mut store, &block2);

    }

    #[test]
    fn test_blocks_reorder() {

        let mut store = store::Store::new(& test_cfg!());

        tx_builder!(bld);

        let block0 = genesis!();
        let block1 = blk!(prev = block0;
            tx!(bld; coinbase => b;11 ),
            tx!(bld; b => c,e )
        );

        let block2 = blk!(prev = block1;
            tx!(bld; coinbase => f;12 ),
            tx!(bld; c => g )
        );

        //        add_block(&mut store, &block0);

        println!("block1 = {:?}", block1);
        //println!("tx1 = {:?}", ::hash::Hash32Buf::double_sha256(&tx1));
        add_block(&mut store, &block0);
        add_block(&mut store, &block2);
        add_block(&mut store, &block1);

    }

}

<commit_msg>Fix slow coning of filesets<commit_after>/// Implements the block_add procedure

/*

Block storing is a tricky part; blocks are stored in the spent-tree and referenced in the
 hash-index

 This can go out of order:  For instance consider 5 blocks added in the order A, B, D, E, C
 (for this pseudocode, each block has the previous letter as prev_block_hash)

 We show the some pseudocode for actions on hashindex (hi) and spent-tree (st),
 for the insertion of this sequence

 insert A:
    st.store_block(A)
    fn do_connect(null,A) =
      (prev = null, no get_or_set)
      hi.set(A)

 insert B:
    st.store_block(B)
    hi.get_or_set(A, guard[B]) returns A
    fn do_connect(A,B) =
      st.connect_block(A,B)
      hi.set(B)

 insert D:
    st.store_block(D)
    hi.get_or_set(C, guard[D]) return none & adds guard[D] at hash C

 insert E:
   st.store_block(E)
   hi.get_or_set(D, guard[E]) return none & adds guard[E] at hash D

 insert C:
   st.store_block(C)
   hi.get_or_set(B, guard[C]) returns B
   fn do_connect(B,C) =
      st.connect_block(B,C)
      hi.set(C) -> fail due to guard([D])

        loop {
            hi.get(C) -> return guard[D]
            do_connect(C,D)
            hi.set(C, guard([D]) -> fail or break
        }

  Now let us consider what happens when C' is inserted *during* processing of B. Copyied from B above:
  B:
    st.store_block(B)
    hi.get_or_set(A, guard[B]) returns A
    fn do_connect(A,B) =
      st.connect_block(A,B)
        < here C' is inserted as B -> guard[C']
      hi.set(B) -> fail due to guard[C']
      loop {
            hi.get(B) -> return guard[C']
            do_connect(B,C')
            hi.set(B, guard([C']) -> success!
        }

*/

use hash::*;
use util::*;
use buffer::*;
use rayon::prelude::*;
use slog ;

use store::Store;
use transaction;
use merkle_tree;
use block::*;
use store::Record;
use store::BlockPtr;
use store::HashIndexGuard;

type BlockResult<T> = Result<T, BlockError>;

/// Returns true if the given hash is the hash of a genesis block
fn is_genesis_block(hash: Hash32) -> bool {
    const HASH_GENESIS: &'static str =
        "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";

    let genesis = Hash32Buf::from_slice(&from_hex_rev(HASH_GENESIS));

    genesis.as_ref() == hash
}

// Connects two blocks (A,B) in the spent-tree and then stores the hash of B in the hash-index
// Connecting the blocks will verify double-spents
//
// It can be that another block C is also waiting for B; this will trigger their connection (B,C) too
// and maybe (C,D)... etcetera
//
// This would be neat to do recursively, but this could exhaust the stack , we use a loop with
// a to_do for connections.
fn connect_block(
    store:           &mut Store,
    this_block_hash: Hash32,
    previous_block:  Option<BlockPtr>,
    this_block:      BlockPtr)

    -> BlockResult<()>
{
    trace!(store.logger, "Connect block";
        "this_hash"  =>  format!("{:?}", this_block_hash),
        "prev_end"   =>  format!("{:?}", previous_block),
        "this_start" =>  format!("{:?}", this_block)
    );

    // we lay connections between the end of one block and the start of this_block
    // prev_end is None only for genesis
    #[derive(Debug)]
    struct Connection {
        block:         BlockPtr,
        block_hash:    Hash32Buf,
        solved_guards: Vec<BlockPtr>
    }

    // connect first block ...
    if let Some(previous_block) = previous_block {
        store.spent_tree.connect_block( &mut store.spent_index, & store.logger, previous_block, this_block) ?;
    }

    // The to_do list contains blocks that are connected to their previous but not yet added to the
    // block-index.
    let mut todo = vec![Connection {
        block:         this_block,
        block_hash:    this_block_hash.as_buf(),
        solved_guards: vec![]
    }];

    while let Some(conn) = todo.pop() {

        trace!(store.logger, "Connect block - set-hash-loop";
            "conn"  => format!("{:?}",   conn));

        // if we can store this hash we can move to the next one
        if store.block_index.set(conn.block_hash.as_ref(), conn.block.to_non_guard(), &conn.solved_guards) {
            trace!(store.logger, "Connect block - set-hash-loop - ok");
            continue;
        }

        let guards = store.block_index.get(conn.block_hash.as_ref());

        if guards.iter().any(|ptr| !ptr.is_guard()) {
            // this is not a guard, this is _this_ block. It seems the block
            // was added by a concurrent user; will do fine.
            trace!(store.logger, "Connect block - set-hash-loop - concurrent add");
            continue;
        }

        //let guards = store.hash_index.get(conn.this_hash);
        todo.push(Connection {
            block: conn.block,
            block_hash: conn.block_hash,
            solved_guards: guards.clone()
        });

        //let guards = store.hash_index.get(conn.this_hash.as_buf());

        for ptr in guards {
            if conn.solved_guards.contains(&ptr) {
                continue;
            }

            let hash = store.get_block_hash(ptr);

            trace!(store.logger, "Connect block - set-hash-loop";
                "guard" => format!("{:?}", ptr),
                "hash" => format!("{:?}",   hash),
                "conn"  => format!("{:?}",   conn));

            store.spent_tree.revolve_orphan_pointers(
                &mut store.transactions,
                &mut store.tx_index,
                ptr
            );

            store.spent_tree.connect_block(&mut store.spent_index, &store.logger, conn.block, ptr)?;

            todo.push(Connection {
                block: ptr,
                block_hash: hash,
                solved_guards: vec![]

            });

        }
    }

    Ok(())
}

/// Returns true if the block is already stored
fn block_exists(store: & mut Store, block_hash: Hash32) -> bool {
    let ptr = store.block_index.get(block_hash);

    ptr.iter().any( | ptr | !ptr.is_guard())

}

/// Verifies and stores the transactions in the block.
/// Also verifies the merkle_root & the amounts
///
/// Returns a list fileptrs to the transactions
///
fn verify_and_store_transactions(store: &mut Store, block: &Block) -> BlockResult<Vec<Record>> {

    if block.to_raw().len() > ::block::MAX_BLOCK_SIZE {
        panic!("Block too large");
        return Err(BlockError::BlockTooLarge);
    }

    // we map the transactions to a tuple of hash and a record
    let tuples: Vec<(Hash32Buf, Record)> = block.txs.iter().map(|tx| {

        let hash_buf = Hash32Buf::double_sha256(tx.to_raw());

        let res = tx.verify_and_store(&mut store.tx_index, &mut store.transactions, hash_buf.as_ref()).unwrap();

        // AlreadyExists and VerifiedAndStored are both ok here
        let ptr = match res {
            transaction::TransactionOk::AlreadyExists(ptr) => ptr,
            transaction::TransactionOk::VerifiedAndStored(ptr) => ptr
        };

        let rec = Record::new_transaction(ptr);

        (hash_buf, rec)
    }).collect();

    // the result of above loop is a hash and a ptr for each transaction; split them.
    let (hashes, ptrs): (Vec<Hash32Buf>, Vec<Record>) = tuples.into_iter().unzip();

    // check merkle roots
    let calculated_merkle_root = merkle_tree::get_merkle_root(hashes);
    block.verify_merkle_root(calculated_merkle_root.as_ref()).unwrap();

    // construct records for in the spent-tree
    let mut records: Vec<Record> = Vec::new();
    for (tx,rec) in block.txs.iter().zip(ptrs) {
        records.push(rec);
        records.append(&mut tx.get_output_records(store));
    }

    Ok(records)
}

/// Validates and stores a block;
///
pub fn add_block(store: &mut Store, buffer: &[u8]) {

    // parse
    let block      = Block::new(buffer) .unwrap();
    let block_hash = Hash32Buf::double_sha256( block.header.to_raw());

    let block_logger = slog::Logger::new(&store.logger, o!());
    info!(block_logger, "add_block - start"; "hash" => format!("{:?}", block_hash));

    // already done?
    if block_exists(store, block_hash.as_ref()) {
        info!(store.logger, "add_block - Block already exists");
        return;
    }

    // check and store the transactions in block_content and check the merkle_root
    let spent_tree_ptrs = verify_and_store_transactions(store, &block).unwrap();

    // store the blockheader in block_content
    let block_header_ptr = store.block_headers.write( &block.header.to_raw());

    // we also store the txcount, although we only use it for a reindex benchmark
    let _ = store.block_headers.write_fixed( &block.txs.len());

    // store the block in the spent_tree
    /*
    let block_ptr       = store.spent_tree.store_block(block_header_ptr, spent_tree_ptrs);

    if is_genesis_block(block_hash.as_ref()) {

        info ! (block_logger, "add_block - storing genesis block");

        // there is None previous block, but we call connect_block anyway as this will also
        // connect to next blocks if they are already in
        connect_block(store, block_hash.as_ref(), None, block_ptr).unwrap();
    }
    else {

        // we retrieve the pointer to the end of the previous block from the hash-index
        // if it is not yet in, this hash will be inserted as a guard-block
        let previous_block = store.block_index.get_or_set( block.header.prev_hash, block_ptr.to_guard());

        info! (block_logger, "add_block - tranactions done";
            "previous" => format!("{:?}", block.header.prev_hash),
            "ptr" => format!("{:?}", previous_block));

        // if it is in, we will connect
        if let Some(previous_block) = previous_block {

            connect_block(store, block_hash.as_ref(), Some(previous_block), block_ptr).unwrap();
        }

    }
*/
    // TODO verify amounts
    // TODO verify PoW
    // TODO verify header-syntax

    info!(block_logger, "add_block - done");
}

#[cfg(test)]
mod tests {

    use store;
    use super::*;

    use rayon::prelude::*;
    #[test]
    fn test_clone_into_thread() {

        struct X { data: Vec<u32> };
        impl Clone for X {
            fn clone(&self) -> X { X { data: self.data.clone() } }
        }
        let mut x = X { data: vec![1,2,3,4,5,6,7,8,9,10]};

        let y = vec![10,11,12,13,14,15,16,17,18,19,20];

        y.into_par_iter().map(|z| {
            let u = &mut x.clone(); // is this possible?
            println!("{:?} {:?} ", z, u.data); u.data.push(2);
        });
    }

    #[test]
    fn test_block_simple() {

        let mut store = store::Store::new(& test_cfg!());

        tx_builder!(bld);

        let block0 = genesis!();

        let block1 = blk!(prev = block0;
            tx!(bld; coinbase => b;11 ),
            tx!(bld; b => c,e )
        );

        let block2 = blk!(prev = block1;
            tx!(bld; coinbase => f;12 ),
            tx!(bld; c => g )
        );

        add_block(&mut store, &block0);
        add_block(&mut store, &block1);
        add_block(&mut store, &block2);

    }

    #[test]
    fn test_blocks_reorder() {

        let mut store = store::Store::new(& test_cfg!());

        tx_builder!(bld);

        let block0 = genesis!();
        let block1 = blk!(prev = block0;
            tx!(bld; coinbase => b;11 ),
            tx!(bld; b => c,e )
        );

        let block2 = blk!(prev = block1;
            tx!(bld; coinbase => f;12 ),
            tx!(bld; c => g )
        );

        //        add_block(&mut store, &block0);

        println!("block1 = {:?}", block1);
        //println!("tx1 = {:?}", ::hash::Hash32Buf::double_sha256(&tx1));
        add_block(&mut store, &block0);
        add_block(&mut store, &block2);
        add_block(&mut store, &block1);

    }

}

<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

use crate::bindings::*;
use libc::{c_char, c_int, size_t};
use std::os::raw::c_void;
use std::ptr;
use std::slice;
// error handling functions
// pub fn xmlSetGenericErrorFunc(ctx: *mut c_void, handler: *mut c_void);
// pub fn xmlThrDefSetGenericErrorFunc(ctx: *mut c_void, handler: *mut c_void);

// Taken from Nokogiri (https://github.com/sparklemotion/nokogiri/blob/24bb843327306d2d71e4b2dc337c1e327cbf4516/ext/nokogiri/xml_document.c#L64)
pub fn xmlNodeRecursivelyRemoveNs(node: xmlNodePtr) {
  unsafe {
    let mut property: xmlAttrPtr;

    xmlSetNs(node, ptr::null_mut());
    let mut child: xmlNodePtr = (*node).children;
    while !child.is_null() {
      xmlNodeRecursivelyRemoveNs(child);
      child = (*child).next;
    }

    if (((*node).type_ == xmlElementType_XML_ELEMENT_NODE)
      || ((*node).type_ == xmlElementType_XML_XINCLUDE_START)
      || ((*node).type_ == xmlElementType_XML_XINCLUDE_END))
      && !(*node).nsDef.is_null()
    {
      xmlFreeNsList((*node).nsDef);
      (*node).nsDef = ptr::null_mut();
    }

    if (*node).type_ == xmlElementType_XML_ELEMENT_NODE && !(*node).properties.is_null() {
      property = (*node).properties;
      while !property.is_null() {
        if !(*property).ns.is_null() {
          (*property).ns = ptr::null_mut();
        }
        property = (*property).next;
      }
    }
  }
}
pub fn xmlGetDoc(cur: xmlNodePtr) -> xmlDocPtr {
  unsafe { (*cur).doc }
}
pub fn xmlNextNsSibling(ns: xmlNsPtr) -> xmlNsPtr {
  unsafe { (*ns).next }
}
pub fn xmlNsPrefix(ns: xmlNsPtr) -> *const c_char {
  unsafe { (*ns).prefix as *const c_char }
}
pub fn xmlNsHref(ns: xmlNsPtr) -> *const c_char {
  unsafe { (*ns).href as *const c_char }
}
pub fn xmlNodeNsDeclarations(cur: xmlNodePtr) -> xmlNsPtr {
  unsafe { (*cur).nsDef }
}
pub fn xmlNodeNs(cur: xmlNodePtr) -> xmlNsPtr {
  unsafe { (*cur).ns }
}

pub fn xmlNextPropertySibling(attr: xmlAttrPtr) -> xmlAttrPtr {
  unsafe { (*attr).next }
}
pub fn xmlAttrName(attr: xmlAttrPtr) -> *const c_char {
  unsafe { (*attr).name as *const c_char }
}
pub fn xmlGetFirstProperty(node: xmlNodePtr) -> xmlAttrPtr {
  unsafe { (*node).properties }
}
pub fn xmlGetNodeType(cur: xmlNodePtr) -> u32 {
  unsafe { (*cur).type_ }
}

pub fn xmlGetParent(cur: xmlNodePtr) -> xmlNodePtr {
  unsafe { (*cur).parent }
}
pub fn xmlGetFirstChild(cur: xmlNodePtr) -> xmlNodePtr {
  unsafe { (*cur).children }
}
pub fn xmlPrevSibling(cur: xmlNodePtr) -> xmlNodePtr {
  unsafe { (*cur).prev }
}

// helper for tree
pub fn xmlNextSibling(cur: xmlNodePtr) -> xmlNodePtr {
  unsafe { (*cur).next }
}

pub fn xmlNodeGetName(cur: xmlNodePtr) -> *const c_char {
  unsafe { (*cur).name as *const c_char }
}

pub fn setIndentTreeOutput(indent: c_int) {
  unsafe {
    let xml_indent_tree_output_ptr = __xmlIndentTreeOutput();
    (*xml_indent_tree_output_ptr) = indent;
  }
}

// dummy function: no debug output at all
fn _ignoreInvalidTagsErrorFunc(_user_data: *mut c_void, error: xmlErrorPtr) {
  unsafe {
    if !error.is_null() && (*error).code as u32 == xmlParserErrors_XML_HTML_UNKNOWN_TAG {
      // do not record invalid, in fact (out of despair) claim we ARE well-formed, when a tag is invalid.

      HACKY_WELL_FORMED = true;
    }
  }
  return;
}

pub fn setWellFormednessHandler(ctxt: *mut xmlParserCtxt) {
  unsafe {
    HACKY_WELL_FORMED = false;
    xmlSetStructuredErrorFunc(ctxt as *mut c_void, Some(_ignoreInvalidTagsErrorFunc));
  }
}
// helper for parser
pub fn htmlWellFormed(ctxt: *mut xmlParserCtxt) -> bool {
  unsafe { (!ctxt.is_null() && (*ctxt).wellFormed > 0) || HACKY_WELL_FORMED }
}

// helper for xpath
pub fn xmlXPathObjectNumberOfNodes(val: xmlXPathObjectPtr) -> c_int {
  unsafe {
    if val.is_null() {
      -1
    } else if (*val).nodesetval.is_null() {
      -2
    } else {
      (*(*val).nodesetval).nodeNr
    }
  }
}

pub fn xmlXPathObjectGetNodes(val: xmlXPathObjectPtr, size: size_t) -> Vec<xmlNodePtr> {
  unsafe { slice::from_raw_parts((*(*val).nodesetval).nodeTab, size).to_vec() }
}
<commit_msg>Fix c_helper.rs permissions<commit_after>#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

use crate::bindings::*;
use libc::{c_char, c_int, size_t};
use std::os::raw::c_void;
use std::ptr;
use std::slice;
// error handling functions
// pub fn xmlSetGenericErrorFunc(ctx: *mut c_void, handler: *mut c_void);
// pub fn xmlThrDefSetGenericErrorFunc(ctx: *mut c_void, handler: *mut c_void);

// Taken from Nokogiri (https://github.com/sparklemotion/nokogiri/blob/24bb843327306d2d71e4b2dc337c1e327cbf4516/ext/nokogiri/xml_document.c#L64)
pub fn xmlNodeRecursivelyRemoveNs(node: xmlNodePtr) {
  unsafe {
    let mut property: xmlAttrPtr;

    xmlSetNs(node, ptr::null_mut());
    let mut child: xmlNodePtr = (*node).children;
    while !child.is_null() {
      xmlNodeRecursivelyRemoveNs(child);
      child = (*child).next;
    }

    if (((*node).type_ == xmlElementType_XML_ELEMENT_NODE)
      || ((*node).type_ == xmlElementType_XML_XINCLUDE_START)
      || ((*node).type_ == xmlElementType_XML_XINCLUDE_END))
      && !(*node).nsDef.is_null()
    {
      xmlFreeNsList((*node).nsDef);
      (*node).nsDef = ptr::null_mut();
    }

    if (*node).type_ == xmlElementType_XML_ELEMENT_NODE && !(*node).properties.is_null() {
      property = (*node).properties;
      while !property.is_null() {
        if !(*property).ns.is_null() {
          (*property).ns = ptr::null_mut();
        }
        property = (*property).next;
      }
    }
  }
}
pub fn xmlGetDoc(cur: xmlNodePtr) -> xmlDocPtr {
  unsafe { (*cur).doc }
}
pub fn xmlNextNsSibling(ns: xmlNsPtr) -> xmlNsPtr {
  unsafe { (*ns).next }
}
pub fn xmlNsPrefix(ns: xmlNsPtr) -> *const c_char {
  unsafe { (*ns).prefix as *const c_char }
}
pub fn xmlNsHref(ns: xmlNsPtr) -> *const c_char {
  unsafe { (*ns).href as *const c_char }
}
pub fn xmlNodeNsDeclarations(cur: xmlNodePtr) -> xmlNsPtr {
  unsafe { (*cur).nsDef }
}
pub fn xmlNodeNs(cur: xmlNodePtr) -> xmlNsPtr {
  unsafe { (*cur).ns }
}

pub fn xmlNextPropertySibling(attr: xmlAttrPtr) -> xmlAttrPtr {
  unsafe { (*attr).next }
}
pub fn xmlAttrName(attr: xmlAttrPtr) -> *const c_char {
  unsafe { (*attr).name as *const c_char }
}
pub fn xmlGetFirstProperty(node: xmlNodePtr) -> xmlAttrPtr {
  unsafe { (*node).properties }
}
pub fn xmlGetNodeType(cur: xmlNodePtr) -> u32 {
  unsafe { (*cur).type_ }
}

pub fn xmlGetParent(cur: xmlNodePtr) -> xmlNodePtr {
  unsafe { (*cur).parent }
}
pub fn xmlGetFirstChild(cur: xmlNodePtr) -> xmlNodePtr {
  unsafe { (*cur).children }
}
pub fn xmlPrevSibling(cur: xmlNodePtr) -> xmlNodePtr {
  unsafe { (*cur).prev }
}

// helper for tree
pub fn xmlNextSibling(cur: xmlNodePtr) -> xmlNodePtr {
  unsafe { (*cur).next }
}

pub fn xmlNodeGetName(cur: xmlNodePtr) -> *const c_char {
  unsafe { (*cur).name as *const c_char }
}

pub fn setIndentTreeOutput(indent: c_int) {
  unsafe {
    let xml_indent_tree_output_ptr = __xmlIndentTreeOutput();
    (*xml_indent_tree_output_ptr) = indent;
  }
}

// dummy function: no debug output at all
fn _ignoreInvalidTagsErrorFunc(_user_data: *mut c_void, error: xmlErrorPtr) {
  unsafe {
    if !error.is_null() && (*error).code as u32 == xmlParserErrors_XML_HTML_UNKNOWN_TAG {
      // do not record invalid, in fact (out of despair) claim we ARE well-formed, when a tag is invalid.

      HACKY_WELL_FORMED = true;
    }
  }
  return;
}

pub fn setWellFormednessHandler(ctxt: *mut xmlParserCtxt) {
  unsafe {
    HACKY_WELL_FORMED = false;
    xmlSetStructuredErrorFunc(ctxt as *mut c_void, Some(_ignoreInvalidTagsErrorFunc));
  }
}
// helper for parser
pub fn htmlWellFormed(ctxt: *mut xmlParserCtxt) -> bool {
  unsafe { (!ctxt.is_null() && (*ctxt).wellFormed > 0) || HACKY_WELL_FORMED }
}

// helper for xpath
pub fn xmlXPathObjectNumberOfNodes(val: xmlXPathObjectPtr) -> c_int {
  unsafe {
    if val.is_null() {
      -1
    } else if (*val).nodesetval.is_null() {
      -2
    } else {
      (*(*val).nodesetval).nodeNr
    }
  }
}

pub fn xmlXPathObjectGetNodes(val: xmlXPathObjectPtr, size: size_t) -> Vec<xmlNodePtr> {
  unsafe { slice::from_raw_parts((*(*val).nodesetval).nodeTab, size).to_vec() }
}
<|endoftext|>


<commit_before>use ahash::{CallHasher, RandomState};
use criterion::*;
use fxhash::FxHasher;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher, BuildHasher};

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
fn aeshash<H: Hash>(b: &H) -> u64 {
    let hasher = RandomState::with_seeds(1, 2, 3, 4).build_hasher();
    b.get_hash(hasher)
}
#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes")))]
fn aeshash<H: Hash>(_b: &H) -> u64 {
    panic!("aes must be enabled")
}

#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes")))]
fn fallbackhash<H: Hash>(b: &H) -> u64 {
    let hasher = RandomState::with_seeds(1, 2, 3, 4).build_hasher();
    H::get_hash(b, hasher)
}
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
fn fallbackhash<H: Hash>(_b: &H) -> u64 {
    panic!("aes must be disabled")
}

fn fnvhash<H: Hash>(b: &H) -> u64 {
    let mut hasher = fnv::FnvHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn siphash<H: Hash>(b: &H) -> u64 {
    let mut hasher = DefaultHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn fxhash<H: Hash>(b: &H) -> u64 {
    let mut hasher = FxHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn seahash<H: Hash>(b: &H) -> u64 {
    let mut hasher = seahash::SeaHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

const STRING_LENGTHS: [u32; 12] = [1, 3, 4, 7, 8, 15, 16, 24, 33, 68, 132, 1024];

fn gen_strings() -> Vec<String> {
    STRING_LENGTHS
        .iter()
        .map(|len| {
            let mut string = String::default();
            for pos in 1..=*len {
                let c = (48 + (pos % 10) as u8) as char;
                string.push(c);
            }
            string
        })
        .collect()
}

const U8_VALUES: [u8; 1] = [123];
const U16_VALUES: [u16; 1] = [1234];
const U32_VALUES: [u32; 1] = [12345678];
const U64_VALUES: [u64; 1] = [1234567890123456];
const U128_VALUES: [u128; 1] = [12345678901234567890123456789012];

fn bench_ahash(c: &mut Criterion) {
    c.bench(
        "aeshash",
        ParameterizedBenchmark::new("u8", |b, &s| b.iter(|| black_box(aeshash(s))), &U8_VALUES),
    );
    c.bench(
        "aeshash",
        ParameterizedBenchmark::new("u16", |b, &s| b.iter(|| black_box(aeshash(s))), &U16_VALUES),
    );
    c.bench(
        "aeshash",
        ParameterizedBenchmark::new("u32", |b, &s| b.iter(|| black_box(aeshash(s))), &U32_VALUES),
    );
    c.bench(
        "aeshash",
        ParameterizedBenchmark::new("u64", |b, &s| b.iter(|| black_box(aeshash(s))), &U64_VALUES),
    );
    c.bench(
        "aeshash",
        ParameterizedBenchmark::new("u128", |b, &s| b.iter(|| black_box(aeshash(s))), &U128_VALUES),
    );
    c.bench(
        "aeshash",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(aeshash(s))), gen_strings()),
    );
}

fn bench_fallback(c: &mut Criterion) {
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u8", |b, &s| b.iter(|| black_box(fallbackhash(s))), &U8_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u16", |b, &s| b.iter(|| black_box(fallbackhash(s))), &U16_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u32", |b, &s| b.iter(|| black_box(fallbackhash(s))), &U32_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u64", |b, &s| b.iter(|| black_box(fallbackhash(s))), &U64_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u128", |b, &s| b.iter(|| black_box(fallbackhash(s))), &U128_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(fallbackhash(s))), gen_strings()),
    );
}

fn bench_fx(c: &mut Criterion) {
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u8", |b, &s| b.iter(|| black_box(fxhash(s))), &U8_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u16", |b, &s| b.iter(|| black_box(fxhash(s))), &U16_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u32", |b, &s| b.iter(|| black_box(fxhash(s))), &U32_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u64", |b, &s| b.iter(|| black_box(fxhash(s))), &U64_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u128", |b, &s| b.iter(|| black_box(fxhash(s))), &U128_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(fxhash(s))), gen_strings()),
    );
}

fn bench_fnv(c: &mut Criterion) {
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u8", |b, &s| b.iter(|| black_box(fnvhash(s))), &U8_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u16", |b, &s| b.iter(|| black_box(fnvhash(s))), &U16_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u32", |b, &s| b.iter(|| black_box(fnvhash(s))), &U32_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u64", |b, &s| b.iter(|| black_box(fnvhash(s))), &U64_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u128", |b, &s| b.iter(|| black_box(fnvhash(s))), &U128_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(fnvhash(s))), gen_strings()),
    );
}

fn bench_sea(c: &mut Criterion) {
    c.bench(
        "sea",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(seahash(s))), gen_strings()),
    );
}

fn bench_sip(c: &mut Criterion) {
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u8", |b, &s| b.iter(|| black_box(siphash(s))), &U8_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u16", |b, &s| b.iter(|| black_box(siphash(s))), &U16_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u32", |b, &s| b.iter(|| black_box(siphash(s))), &U32_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u64", |b, &s| b.iter(|| black_box(siphash(s))), &U64_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u128", |b, &s| b.iter(|| black_box(siphash(s))), &U128_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(siphash(s))), gen_strings()),
    );
}

criterion_main!(benches);
criterion_group!(
    benches,
    bench_ahash,
    bench_fallback,
    bench_fx,
    bench_fnv,
    bench_sea,
    bench_sip
);
<commit_msg>Change bench to use specialization via type parameter<commit_after>use ahash::{CallHasher, RandomState};
use criterion::*;
use fxhash::FxHasher;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher, BuildHasher};

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
fn aeshash<H: Hash>(b: &H) -> u64 {
    let hasher = RandomState::with_seeds(1, 2, 3, 4).build_hasher();
    H::get_hash(b, hasher)
}
#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes")))]
fn aeshash<H: Hash>(_b: &H) -> u64 {
    panic!("aes must be enabled")
}

#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes")))]
fn fallbackhash<H: Hash>(b: &H) -> u64 {
    let hasher = RandomState::with_seeds(1, 2, 3, 4).build_hasher();
    H::get_hash(b, hasher)
}
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
fn fallbackhash<H: Hash>(_b: &H) -> u64 {
    panic!("aes must be disabled")
}

fn fnvhash<H: Hash>(b: &H) -> u64 {
    let mut hasher = fnv::FnvHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn siphash<H: Hash>(b: &H) -> u64 {
    let mut hasher = DefaultHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn fxhash<H: Hash>(b: &H) -> u64 {
    let mut hasher = FxHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

fn seahash<H: Hash>(b: &H) -> u64 {
    let mut hasher = seahash::SeaHasher::default();
    b.hash(&mut hasher);
    hasher.finish()
}

const STRING_LENGTHS: [u32; 12] = [1, 3, 4, 7, 8, 15, 16, 24, 33, 68, 132, 1024];

fn gen_strings() -> Vec<String> {
    STRING_LENGTHS
        .iter()
        .map(|len| {
            let mut string = String::default();
            for pos in 1..=*len {
                let c = (48 + (pos % 10) as u8) as char;
                string.push(c);
            }
            string
        })
        .collect()
}

const U8_VALUES: [u8; 1] = [123];
const U16_VALUES: [u16; 1] = [1234];
const U32_VALUES: [u32; 1] = [12345678];
const U64_VALUES: [u64; 1] = [1234567890123456];
const U128_VALUES: [u128; 1] = [12345678901234567890123456789012];

fn bench_ahash(c: &mut Criterion) {
    c.bench(
        "aeshash",
        ParameterizedBenchmark::new("u8", |b, &s| b.iter(|| black_box(aeshash(s))), &U8_VALUES),
    );
    c.bench(
        "aeshash",
        ParameterizedBenchmark::new("u16", |b, &s| b.iter(|| black_box(aeshash(s))), &U16_VALUES),
    );
    c.bench(
        "aeshash",
        ParameterizedBenchmark::new("u32", |b, &s| b.iter(|| black_box(aeshash(s))), &U32_VALUES),
    );
    c.bench(
        "aeshash",
        ParameterizedBenchmark::new("u64", |b, &s| b.iter(|| black_box(aeshash(s))), &U64_VALUES),
    );
    c.bench(
        "aeshash",
        ParameterizedBenchmark::new("u128", |b, &s| b.iter(|| black_box(aeshash(s))), &U128_VALUES),
    );
    c.bench(
        "aeshash",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(aeshash(s))), gen_strings()),
    );
}

fn bench_fallback(c: &mut Criterion) {
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u8", |b, &s| b.iter(|| black_box(fallbackhash(s))), &U8_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u16", |b, &s| b.iter(|| black_box(fallbackhash(s))), &U16_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u32", |b, &s| b.iter(|| black_box(fallbackhash(s))), &U32_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u64", |b, &s| b.iter(|| black_box(fallbackhash(s))), &U64_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("u128", |b, &s| b.iter(|| black_box(fallbackhash(s))), &U128_VALUES),
    );
    c.bench(
        "fallback",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(fallbackhash(s))), gen_strings()),
    );
}

fn bench_fx(c: &mut Criterion) {
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u8", |b, &s| b.iter(|| black_box(fxhash(s))), &U8_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u16", |b, &s| b.iter(|| black_box(fxhash(s))), &U16_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u32", |b, &s| b.iter(|| black_box(fxhash(s))), &U32_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u64", |b, &s| b.iter(|| black_box(fxhash(s))), &U64_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("u128", |b, &s| b.iter(|| black_box(fxhash(s))), &U128_VALUES),
    );
    c.bench(
        "fx",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(fxhash(s))), gen_strings()),
    );
}

fn bench_fnv(c: &mut Criterion) {
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u8", |b, &s| b.iter(|| black_box(fnvhash(s))), &U8_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u16", |b, &s| b.iter(|| black_box(fnvhash(s))), &U16_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u32", |b, &s| b.iter(|| black_box(fnvhash(s))), &U32_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u64", |b, &s| b.iter(|| black_box(fnvhash(s))), &U64_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("u128", |b, &s| b.iter(|| black_box(fnvhash(s))), &U128_VALUES),
    );
    c.bench(
        "fnv",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(fnvhash(s))), gen_strings()),
    );
}

fn bench_sea(c: &mut Criterion) {
    c.bench(
        "sea",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(seahash(s))), gen_strings()),
    );
}

fn bench_sip(c: &mut Criterion) {
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u8", |b, &s| b.iter(|| black_box(siphash(s))), &U8_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u16", |b, &s| b.iter(|| black_box(siphash(s))), &U16_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u32", |b, &s| b.iter(|| black_box(siphash(s))), &U32_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u64", |b, &s| b.iter(|| black_box(siphash(s))), &U64_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("u128", |b, &s| b.iter(|| black_box(siphash(s))), &U128_VALUES),
    );
    c.bench(
        "sip",
        ParameterizedBenchmark::new("string", |b, s| b.iter(|| black_box(siphash(s))), gen_strings()),
    );
}

criterion_main!(benches);
criterion_group!(
    benches,
    bench_ahash,
    bench_fallback,
    bench_fx,
    bench_fnv,
    bench_sea,
    bench_sip
);
<|endoftext|>


<commit_before>use crate::get_book_dir;
use clap::{App, ArgMatches, SubCommand};
use mdbook::errors::*;
use mdbook::MDBook;
use std::fs;
use std::path::Path;

// Create clap subcommand arguments
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
    SubCommand::with_name("clean")
        .about("Deletes a built book")
        .arg_from_usage(
            "-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
             Relative paths are interpreted relative to the book's root directory.{n}\
             Running this command deletes this directory.{n}\
             If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.'",
        )
        .arg_from_usage(
            "[dir] 'Root directory for the book{n}\
             (Defaults to the Current Directory when omitted)'",
        )
}

// Clean command implementation
pub fn execute(args: &ArgMatches) -> mdbook::errors::Result<()> {
    let book_dir = get_book_dir(args);
    let book = MDBook::load(&book_dir)?;

    let dir_to_remove = match args.value_of("dest-dir") {
        Some(dest_dir) => dest_dir.into(),
        None => book.root.join(&book.config.build.build_dir),
    };

    let path_to_dir_to_remove = Path::new(&dir_to_remove);
    if path_to_dir_to_remove.exists() {
        fs::remove_dir_all(&dir_to_remove).chain_err(|| "Unable to remove the build directory")?;
    }

    Ok(())
}
<commit_msg>Revert "Fix (command:clean): removes error message 'dir not found' if 'clean' is run multiple times"<commit_after>use crate::get_book_dir;
use clap::{App, ArgMatches, SubCommand};
use mdbook::errors::*;
use mdbook::MDBook;
use std::fs;

// Create clap subcommand arguments
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
    SubCommand::with_name("clean")
        .about("Deletes a built book")
        .arg_from_usage(
            "-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
             Relative paths are interpreted relative to the book's root directory.{n}\
             Running this command deletes this directory.{n}\
             If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.'",
        )
        .arg_from_usage(
            "[dir] 'Root directory for the book{n}\
             (Defaults to the Current Directory when omitted)'",
        )
}

// Clean command implementation
pub fn execute(args: &ArgMatches) -> mdbook::errors::Result<()> {
    let book_dir = get_book_dir(args);
    let book = MDBook::load(&book_dir)?;

    let dir_to_remove = match args.value_of("dest-dir") {
        Some(dest_dir) => dest_dir.into(),
        None => book.root.join(&book.config.build.build_dir),
    };
    fs::remove_dir_all(&dir_to_remove).chain_err(|| "Unable to remove the build directory")?;

    Ok(())
}
<|endoftext|>


<commit_before>extern crate xmltree;

use std::borrow::Cow;
use std::fs::File;
use std::io::Cursor;
use xmltree::*;

#[test]
fn test_01() {
    let e: Element = Element::parse(File::open("tests/data/01.xml").unwrap()).unwrap();
    println!("E:=======\n{:#?}", e);
    assert_eq!(e.name, "project");
    let e2: &Element = e
        .get_child("libraries")
        .expect("Missing libraries child element");
    assert_eq!(e2.name, "libraries");

    assert!(e.get_child("doesnotexist").is_none());

    let mut buf = Vec::new();
    e.write(&mut buf).unwrap();

    let e2 = Element::parse(Cursor::new(buf)).unwrap();
    println!("E2:======\n{:#?}", e2);

    assert_eq!(e, e2);
}

#[test]
fn test_02() {
    let e: Element = Element::parse(File::open("tests/data/02.xml").unwrap()).unwrap();
    println!("{:#?}", e);
}

#[test]
fn test_03() {
    let e: Element = Element::parse(File::open("tests/data/03.xml").unwrap()).unwrap();
    println!("{:#?}", e);
}

#[test]
fn test_04() {
    let e: Element = Element::parse(File::open("tests/data/04.xml").unwrap()).unwrap();
    println!("{:#?}", e);
    let pi = e.children[0].as_processing_instruction();
    assert!(pi.is_some());
    let pi = pi.unwrap();
    assert_eq!(pi.0, "pi");
    assert_eq!(pi.1.unwrap(), "foo=\"blah\"");
}

#[test]
fn test_parse_all() {
    let nodes = Element::parse_all(File::open("tests/data/04.xml").unwrap()).unwrap();
    println!("{:#?}", nodes);
    assert_eq!(nodes.len(), 4);
    assert!(nodes[0].as_comment().is_some());
}

#[test]
fn test_no_root_node() {
    let result = Element::parse_all(File::open("tests/data/05.xml").unwrap());
    assert!(result.is_err())
}

#[test]
fn test_rw() {
    let e: Element = Element::parse(File::open("tests/data/rw.xml").unwrap()).unwrap();

    let mut buf = Vec::new();
    e.write(&mut buf).unwrap();

    let e2 = Element::parse(Cursor::new(buf)).unwrap();

    assert_eq!(e, e2);
}

#[test]
fn test_mut() {
    let mut e: Element = Element::parse(File::open("tests/data/rw.xml").unwrap()).unwrap();
    {
        let name = e.get_mut_child("name").unwrap();
        name.attributes.insert("suffix".to_owned(), "mr".to_owned());
    }
}

#[test]
fn test_mal_01() {
    // some tests for error handling

    let data = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <names>
            <name first="bob" last="jones />
            <name first="elizabeth" last="smith" />
        </names>
    "##;

    let names_element = Element::parse(data.as_bytes());
    if let Err(ParseError::MalformedXml(..)) = names_element {
        // OK
    } else {
        panic!("unexpected parse result");
    }
    println!("{:?}", names_element);
}

#[test]
fn test_mal_02() {
    // some tests for error handling

    let data = r##"
            this is not even close
            to XML
    "##;

    let names_element = Element::parse(data.as_bytes());
    if let Err(ParseError::MalformedXml(..)) = names_element {
        // OK
    } else {
        panic!("unexpected parse result");
    }
    println!("{:?}", names_element);
}

#[test]
fn test_mal_03() {
    // some tests for error handling

    let data = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <names>
            <name first="bob" last="jones"></badtag>
            <name first="elizabeth" last="smith" />
        </names>
    "##;

    let names_element = Element::parse(data.as_bytes());
    if let Err(ParseError::MalformedXml(..)) = names_element {
        // OK
    } else {
        panic!("unexpected parse result");
    }
    println!("{:?}", names_element);
}

#[test]
fn test_new() {
    let e = Element::new("foo");
    assert_eq!(e.name.as_str(), "foo");
    assert_eq!(e.attributes.len(), 0);
    assert_eq!(e.children.len(), 0);
    // assert_eq!(e.text, None);
}

#[test]
fn test_take() {
    let data_xml_1 = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <names>
            <name first="bob" last="jones"></name>
            <name first="elizabeth" last="smith" />
            <remove_me key="value">
                <child />
            </remove_me>
        </names>
    "##;

    let data_xml_2 = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <names>
            <name first="bob" last="jones"></name>
            <name first="elizabeth" last="smith" />
        </names>
    "##;

    let mut data_1 = Element::parse(data_xml_1.as_bytes()).unwrap();
    let data_2 = Element::parse(data_xml_2.as_bytes()).unwrap();

    if let Some(removed) = data_1.take_child("remove_me") {
        assert_eq!(removed.children.len(), 1);
    } else {
        panic!("take_child failed");
    }

    assert_eq!(data_1, data_2);
}

#[test]
fn test_ns_rw() {
    {
        let e: Element = Element::parse(File::open("tests/data/ns1.xml").unwrap()).unwrap();

        let mut buf = Vec::new();
        e.write(&mut buf).unwrap();

        let e2 = Element::parse(Cursor::new(buf)).unwrap();

        assert_eq!(e, e2);
    }
    {
        let e: Element = Element::parse(File::open("tests/data/ns2.xml").unwrap()).unwrap();

        let mut buf = Vec::new();
        e.write(&mut buf).unwrap();

        let e2 = Element::parse(Cursor::new(buf)).unwrap();

        assert_eq!(e, e2);
    }
}

#[test]
fn test_write_with_config() {
    let e: Element = Element::parse(File::open("tests/data/01.xml").unwrap()).unwrap();

    let cfg = EmitterConfig {
        perform_indent: true,
        ..EmitterConfig::default()
    };

    let mut buf = Vec::new();
    e.write_with_config(&mut buf, cfg).unwrap();

    let s = String::from_utf8(buf).unwrap();
    println!("{}", s);
}

#[test]
fn test_ns() {
    let e: Element = Element::parse(File::open("tests/data/ns1.xml").unwrap()).unwrap();

    let htbl = e
        .get_child(("table", "http://www.w3.org/TR/html4/"))
        .unwrap();
    let ftbl = e
        .get_child(("table", "https://www.w3schools.com/furniture"))
        .unwrap();

    assert_ne!(htbl, ftbl);
}

#[test]
fn test_text() {
    let data = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <elem><inner/></elem>
    "##;

    let elem = Element::parse(data.as_bytes()).unwrap();
    assert!(elem.get_text().is_none());

    let data = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <elem>hello world<inner/></elem>
    "##;

    let elem = Element::parse(data.as_bytes()).unwrap();
    assert_eq!(elem.get_text().unwrap(), Cow::Borrowed("hello world"));

    let data = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <elem>hello <inner/>world</elem>
    "##;

    let elem = Element::parse(data.as_bytes()).unwrap();
    assert_eq!(
        elem.get_text().unwrap(),
        Cow::from("hello world".to_owned())
    );

    let data = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <elem>hello <inner/><![CDATA[<world>]]></elem>
    "##;

    let elem = Element::parse(data.as_bytes()).unwrap();
    assert_eq!(
        elem.get_text().unwrap(),
        Cow::from("hello <world>".to_owned())
    );
}
<commit_msg>Updated tests<commit_after>extern crate xmltree;

use std::borrow::Cow;
use std::fs::File;
use std::io::Cursor;
use xmltree::*;

#[test]
fn test_01() {
    let e: Element = Element::parse(File::open("tests/data/01.xml").unwrap()).unwrap();
    println!("E:=======\n{:#?}", e);
    assert_eq!(e.name, "project");
    let e2: &Element = e
        .get_child("libraries")
        .expect("Missing libraries child element");
    assert_eq!(e2.name, "libraries");

    assert!(e.get_child("doesnotexist").is_none());

    let mut buf = Vec::new();
    e.write(&mut buf).unwrap();

    let e2 = Element::parse(Cursor::new(buf)).unwrap();
    println!("E2:======\n{:#?}", e2);

    assert_eq!(e, e2);
}

#[test]
fn test_02() {
    let e: Element = Element::parse(File::open("tests/data/02.xml").unwrap()).unwrap();
    println!("{:#?}", e);
}

#[test]
fn test_03() {
    let e: Element = Element::parse(File::open("tests/data/03.xml").unwrap()).unwrap();
    println!("{:#?}", e);
}

#[test]
fn test_04() {
    let e: Element = Element::parse(File::open("tests/data/04.xml").unwrap()).unwrap();
    println!("{:#?}", e);
    let pi = e.children[0].as_processing_instruction();
    assert!(pi.is_some());
    let pi = pi.unwrap();
    assert_eq!(pi.0, "pi");
    assert_eq!(pi.1.unwrap(), "foo=\"blah\"");
}

#[test]
fn test_parse_all() {
    let nodes = Element::parse_all(File::open("tests/data/04.xml").unwrap()).unwrap();
    println!("{:#?}", nodes);
    assert_eq!(nodes.len(), 4);
    assert!(nodes[0].as_comment().is_some());
}

#[test]
fn test_no_root_node() {
    let result = Element::parse_all(File::open("tests/data/05.xml").unwrap());
    assert!(result.is_err())
}

#[test]
fn test_rw() {
    let e: Element = Element::parse(File::open("tests/data/rw.xml").unwrap()).unwrap();

    let mut buf = Vec::new();
    e.write(&mut buf).unwrap();

    let e2 = Element::parse(Cursor::new(buf)).unwrap();

    assert_eq!(e, e2);
}

#[test]
fn test_mut() {
    let mut e: Element = Element::parse(File::open("tests/data/rw.xml").unwrap()).unwrap();
    {
        let name = e.get_mut_child("name").unwrap();
        name.attributes.insert("suffix".to_owned(), "mr".to_owned());
    }
}

#[test]
fn test_mal_01() {
    // some tests for error handling

    let data = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <names>
            <name first="bob" last="jones />
            <name first="elizabeth" last="smith" />
        </names>
    "##;

    let names_element = Element::parse(data.as_bytes());
    if let Err(ParseError::MalformedXml(..)) = names_element {
        // OK
    } else {
        panic!("unexpected parse result");
    }
    println!("{:?}", names_element);
}

#[test]
fn test_mal_02() {
    // some tests for error handling

    let data = r##"
            this is not even close
            to XML
    "##;

    let names_element = Element::parse(data.as_bytes());
    if let Err(ParseError::MalformedXml(..)) = names_element {
        // OK
    } else {
        panic!("unexpected parse result");
    }
    println!("{:?}", names_element);
}

#[test]
fn test_mal_03() {
    // some tests for error handling

    let data = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <names>
            <name first="bob" last="jones"></badtag>
            <name first="elizabeth" last="smith" />
        </names>
    "##;

    let names_element = Element::parse(data.as_bytes());
    if let Err(ParseError::MalformedXml(..)) = names_element {
        // OK
    } else {
        panic!("unexpected parse result");
    }
    println!("{:?}", names_element);
}

#[test]
fn test_new() {
    let e = Element::new("foo");
    assert_eq!(e.name.as_str(), "foo");
    assert_eq!(e.attributes.len(), 0);
    assert_eq!(e.children.len(), 0);
    // assert_eq!(e.text, None);
}

#[test]
fn test_take() {
    let data_xml_1 = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <names>
            <name first="bob" last="jones"></name>
            <name first="elizabeth" last="smith" />
            <remove_me key="value">
                <child />
            </remove_me>
        </names>
    "##;

    let data_xml_2 = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <names>
            <name first="bob" last="jones"></name>
            <name first="elizabeth" last="smith" />
        </names>
    "##;

    let mut data_1 = Element::parse(data_xml_1.as_bytes()).unwrap();
    let data_2 = Element::parse(data_xml_2.as_bytes()).unwrap();

    if let Some(removed) = data_1.take_child("remove_me") {
        assert_eq!(removed.children.len(), 1);
    } else {
        panic!("take_child failed");
    }

    assert_eq!(data_1, data_2);
}

#[test]
fn test_ns_rw() {
    {
        let e: Element = Element::parse(File::open("tests/data/ns1.xml").unwrap()).unwrap();

        let mut buf = Vec::new();
        e.write(&mut buf).unwrap();

        let e2 = Element::parse(Cursor::new(buf)).unwrap();

        assert_eq!(e, e2);
    }
    {
        let e: Element = Element::parse(File::open("tests/data/ns2.xml").unwrap()).unwrap();

        let mut buf = Vec::new();
        e.write(&mut buf).unwrap();

        let e2 = Element::parse(Cursor::new(buf)).unwrap();

        assert_eq!(e, e2);
    }
}

#[test]
fn test_write_with_config() {
    let e: Element = Element::parse(File::open("tests/data/01.xml").unwrap()).unwrap();

    let cfg = EmitterConfig {
        perform_indent: true,
        ..EmitterConfig::default()
    };

    let mut buf = Vec::new();
    e.write_with_config(&mut buf, cfg).unwrap();

    let s = String::from_utf8(buf).unwrap();
    println!("{}", s);
}

#[test]
fn test_ns() {
    let e: Element = Element::parse(File::open("tests/data/ns1.xml").unwrap()).unwrap();

    let htbl = e
        .get_child(("table", "http://www.w3.org/TR/html4/"))
        .unwrap();
    let ftbl = e
        .get_child(("table", "https://www.w3schools.com/furniture"))
        .unwrap();

    assert_ne!(htbl, ftbl);
}

#[test]
fn test_text() {
    let data = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <elem><inner/></elem>
    "##;

    let elem = Element::parse(data.as_bytes()).unwrap();
    assert!(elem.get_text().is_none());

    let data = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <elem>hello world<inner/></elem>
    "##;

    let elem = Element::parse(data.as_bytes()).unwrap();
    assert_eq!(elem.get_text().unwrap(), Cow::Borrowed("hello world"));

    let data = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <elem>hello <inner/>world</elem>
    "##;

    let elem = Element::parse(data.as_bytes()).unwrap();
    assert_eq!(
        elem.get_text().unwrap(),
        Cow::from("hello world".to_owned())
    );

    let data = r##"
        <?xml version="1.0" encoding="utf-8" standalone="yes"?>
        <elem>hello <inner/><![CDATA[<world>]]></elem>
    "##;

    let elem = Element::parse(data.as_bytes()).unwrap();
    assert_eq!(
        elem.get_text().unwrap(),
        Cow::from("hello <world>".to_owned())
    );
}

#[test]
fn test_nodecl() {
    let mut c = EmitterConfig::new();
    c.write_document_declaration = false;
    let e = Element::new("n");
    let mut output = Vec::new();
    e.write_with_config(&mut output, c).unwrap();
    assert_eq!(String::from_utf8(output).unwrap(), "<n />");
}

#[test]
fn test_decl() {
    let mut c = EmitterConfig::new();
    c.write_document_declaration = true;
    let e = Element::new("n");
    let mut output = Vec::new();
    e.write_with_config(&mut output, c).unwrap();
    assert_eq!(String::from_utf8(output).unwrap(), "<?xml version=\"1.0\" encoding=\"UTF-8\"?><n />");
}<|endoftext|>


<commit_before>extern crate flate2;
extern crate tar;

use std::fs::File;
use flate2::read::GzDecoder;
use tar::Archive;

#[test]
fn targz() {
    let file = File::open("tests/simple.tar.gz").unwrap();
    let gz_decoder = GzDecoder::new(file).unwrap();
    let mut tar = Archive::new(gz_decoder);
    let expected = ["a", "b", "c/", "c/d"];
    let actual: Vec<_> = tar.files_mut().unwrap()
        .map(|f| f.unwrap().header().path().unwrap().to_str().unwrap().to_owned())
        .collect();
    assert_eq!(actual, expected);
}

#[test]
fn single_vol_names() {
    let file = File::open("tests/backups/single_vol/duplicity-full.20150617T182545Z.vol1.difftar.gz").unwrap();
    let gz_decoder = GzDecoder::new(file).unwrap();
    let mut tar = Archive::new(gz_decoder);
    for file in tar.files_mut().unwrap() {
        if let Ok(f) = file {
            println!("{:?} {:?}", f.header().mode(), f.header().path().unwrap())
        }
    }
}

#[test]
fn link() {
    use std::io::Read;

    let file = File::open("tests/link.tar").unwrap();
    let tar = Archive::new(file);
    let contents: Vec<_> = {
        tar.files()
           .unwrap()
           .map(|f| {
               let mut s = String::new();
               f.unwrap().read_to_string(&mut s).unwrap();
               s
           })
           .collect()
    };
    let expected = vec!["file", "file_contents"];
    assert_eq!(contents, expected);
}
<commit_msg>Added tar test on symbolic links<commit_after>extern crate flate2;
extern crate tar;

use std::fs::File;
use flate2::read::GzDecoder;
use tar::Archive;

#[test]
fn targz() {
    let file = File::open("tests/simple.tar.gz").unwrap();
    let gz_decoder = GzDecoder::new(file).unwrap();
    let mut tar = Archive::new(gz_decoder);
    let expected = ["a", "b", "c/", "c/d"];
    let actual: Vec<_> = tar.files_mut()
                            .unwrap()
                            .map(|f| {
                                f.unwrap().header().path().unwrap().to_str().unwrap().to_owned()
                            })
                            .collect();
    assert_eq!(actual, expected);
}

#[test]
fn single_vol_names() {
    let file =
        File::open("tests/backups/single_vol/duplicity-full.20150617T182545Z.vol1.difftar.gz")
            .unwrap();
    let gz_decoder = GzDecoder::new(file).unwrap();
    let mut tar = Archive::new(gz_decoder);
    for file in tar.files_mut().unwrap() {
        if let Ok(f) = file {
            println!("{:?} {:?}", f.header().mode(), f.header().path().unwrap())
        }
    }
}

#[test]
fn link() {
    use std::io::Read;

    let file = File::open("tests/link.tar").unwrap();
    let tar = Archive::new(file);
    let contents: Vec<_> = {
        tar.files()
           .unwrap()
           .map(|f| {
               let mut f = f.unwrap();
               if f.header().entry_type().is_symlink() {
                   let link_name = f.header().link_name().unwrap().unwrap();
                   link_name.to_str().unwrap().to_owned()
               } else {
                   let mut s = String::new();
                   f.read_to_string(&mut s).unwrap();
                   s
               }
           })
           .collect()
    };
    let expected = vec!["file", "file_contents\n"];
    assert_eq!(contents, expected);
}
<|endoftext|>