<commit_before>use hash::HASH_SIZE;
use hash;
use hash::Hash;
use std::net;
use std::collections::VecDeque;
use std::mem;
use std::sync::{Mutex, RwLock};
use std::iter::{Chain, Rev};

#[cfg(test)]
mod tests;

/// System-wide concurrency factor. It's used, for example, to decide the
/// number of remote nodes to interrogate concurrently when performing a
/// network-wide lookup.
pub const ALPHA    : usize = 3;

/// Data structure factor. It's used, among other places, to dictate the
/// size of a K-bucket.
pub const K        : usize = 20;
const BUCKET_DEPTH : usize = K;

/// Routing table with 160 buckets of `BUCKET_DEPTH` (k) node
/// identifiers each, constructed around a parent node ID.
///
/// The structure employs least-recently seen eviction. Conflicts generated
/// by evicting a node by inserting a newer one remain tracked, so they can
/// be resolved later.
pub struct Table {
   buckets   : Vec<Bucket>,
   conflicts : Mutex<Vec<EvictionConflict>>,
   parent_id : Hash,
}

/// ID - Address pair that identifies a unique Subotai node in the network.
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct NodeInfo {
   pub id      : Hash,
   pub address : net::SocketAddr,
}

/// Result of a table lookup.
/// * `Myself`: The requested ID is precisely the parent node.
///
/// * `Found`: The requested ID was found on the table.
///
/// * `ClosestNodes`: The requested ID was not found, but here are the next
///   closest nodes to consult.
///
/// * `Nothing`: The table is empty or the blacklist provided doesn't allow
///   returning any close nodes.
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub enum LookupResult {
   Myself,
   Found(NodeInfo),
   ClosestNodes(Vec<NodeInfo>),
   Nothing,
}

impl Table {
   /// Constructs a routing table based on a parent node id. Other nodes
   /// will be stored in this table based on their distance to the node id provided.
   pub fn new(parent_id: Hash) -> Table {
      Table {
         buckets   : (0..HASH_SIZE).map(|_| Bucket::new()).collect(),
         conflicts : Mutex::new(Vec::new()),
         parent_id : parent_id,
      }
   }

   /// Returns the number of nodes currently on the table.
   pub fn len(&self) -> usize {
      self.buckets.iter().map(|bucket| bucket.entries.read().unwrap().len()).sum()
   }

   /// Inserts a node in the routing table. Employs least-recently-seen eviction
   /// by kicking out the oldest node in case the bucket is full, and registering
   /// an eviction conflict that can be revised later.
   pub fn insert_node(&self, info: NodeInfo) {
      if let Some(index) = self.bucket_for_node(&info.id) {
         let bucket = &self.buckets[index];
         let mut entries = bucket.entries.write().unwrap();

         entries.retain(|ref stored_info| info.id != stored_info.id);
         if entries.len() == BUCKET_DEPTH {
            let conflict = EvictionConflict {
               evicted  : entries.pop_front().unwrap(),
               inserted : info.clone()
            };
            let mut conflicts = self.conflicts.lock().unwrap();
            conflicts.push(conflict);
         }
         entries.push_back(info);
      }
   }

   /// Performs a node lookup on the routing table. The lookup result may
   /// contain the specific node, a list of up to the N closest nodes, or
   /// report that the parent node itself was requested.
   ///
   /// This employs an algorithm I have named "bounce lookup", which obtains
   /// the closest nodes to a given origin walking through the minimum
   /// amount of buckets. It may exist already, but I haven't
   /// found it any other implementation. It consists of:
   ///
   /// * Calculating the XOR distance between the parent node ID and the
   ///   lookup node ID.
   ///
   /// * Checking the buckets indexed by the position of every "1" in said
   ///   distance hash, in descending order.
   ///
   /// * "Bounce" back up, checking the buckets indexed by the position of
   ///   every "0" in that distance hash, in ascending order.
   pub fn lookup(&self, id: &Hash, n: usize, blacklist: Option<&Vec<Hash>>) -> LookupResult {
      if id == &self.parent_id {
         return LookupResult::Myself;
      }

      match self.specific_node(id) {
         Some(info) => LookupResult::Found(info),
         None =>  {
            let closest = self.closest_n_nodes_to(id, n, blacklist);
            if closest.is_empty() {
               LookupResult::Nothing
            } else {
               LookupResult::ClosestNodes(closest)
            }
         }
      }
   }

   /// Returns an iterator over all stored nodes, ordered by ascending
   /// distance to the parent node. This iterator is designed for concurrent
   /// access to the data structure, and as such it isn't guaranteed that it
   /// will return a "snapshot" of all nodes for a specific moment in time.
   /// Buckets already visited may be modified elsewhere through iteraton,
   /// and unvisited buckets may accrue new nodes.
   pub fn all_nodes(&self) -> AllNodes {
      AllNodes {
         table          : self,
         current_bucket : Vec::with_capacity(BUCKET_DEPTH),
         bucket_index   : 0,
      }
   }

   /// Returns an iterator over all stored nodes, ordered by ascending
   /// distance to a given reference ID.
   pub fn closest_nodes_to<'a,'b>(&'a self, id: &'b Hash) -> ClosestNodesTo<'a,'b> {
      let distance = &self.parent_id ^ id;
      let descent  = distance.clone().into_ones().rev();
      let ascent   = distance.into_zeroes();
      let lookup_order = descent.chain(ascent);

      ClosestNodesTo {
         table          : self,
         reference      : id,
         lookup_order   : lookup_order,
         current_bucket : Vec::with_capacity(BUCKET_DEPTH),
      }
   }

   /// Returns a table entry for the specific node with a given hash.
   pub fn specific_node(&self, id: &Hash) -> Option<NodeInfo> {
      if let Some(index) = self.bucket_for_node(id) {
         let entries = &self.buckets[index].entries.read().unwrap();
         return entries.iter().find(|ref info| *id == info.id).cloned();
      }
      None
   }

   /// Bounce lookup algorithm.
   fn closest_n_nodes_to(&self, id: &Hash, n: usize, blacklist: Option<&Vec<Hash>>) -> Vec<NodeInfo> {
      let mut closest = Vec::with_capacity(n);
      let distance = &self.parent_id ^ id;
      let descent  = distance.ones().rev();
      let ascent   = distance.zeroes();
      let lookup_order = descent.chain(ascent);

      for bucket_index in lookup_order {
         let entries = self.buckets[bucket_index].entries.read().unwrap();
         if entries.is_empty() {
            continue;
         }

         let mut nodes_from_bucket = entries.clone().into_iter().collect::<Vec<NodeInfo>>();
         if let Some(blacklist) = blacklist {
            nodes_from_bucket.retain(|node: &NodeInfo| !blacklist.contains(&node.id));
         }

         nodes_from_bucket.sort_by_key(|ref info| &info.id ^ id);
         let space_left = closest.capacity() - closest.len();
         nodes_from_bucket.truncate(space_left);
         closest.append(&mut nodes_from_bucket);

         if closest.len() == closest.capacity() {
            break;
         }
      }
      closest
   }

   /// Returns the appropriate position for a node, by computing
   /// the index where their prefix starts differing. If we are requesting
   /// the bucket for this table's own parent node, it can't be stored.
   fn bucket_for_node(&self, id: &Hash) -> Option<usize> {
       (&self.parent_id ^ id).height()
   }

   fn revert_conflict(&self, conflict: EvictionConflict) {
      if let Some(index) = self.bucket_for_node(&conflict.inserted.id) {
         let mut entries = self.buckets[index].entries.write().unwrap();
         let evictor = &mut entries.iter_mut().find(|ref info| conflict.inserted.id == info.id).unwrap();
         mem::replace::<NodeInfo>(evictor, conflict.evicted);
      }
   }
}

/// Produces copies of all known nodes, ordered in ascending
/// distance from self. It's a weak invariant, i.e. the table
/// may be modified through iteration.
pub struct AllNodes<'a> {
   table          : &'a Table,
   current_bucket : Vec<NodeInfo>,
   bucket_index   : usize,
}

/// Produces copies of all known nodes, ordered in ascending
/// distance from a reference ID.
pub struct ClosestNodesTo<'a, 'b> {
   table          : &'a Table,
   reference      : &'b hash::Hash,
   lookup_order   : Chain<Rev<hash::IntoOnes>, hash::IntoZeroes>,
   current_bucket : Vec<NodeInfo>,
}

/// Represents a conflict derived from attempting to insert a node in a full
/// bucket.
#[derive(Debug,Clone)]
struct EvictionConflict {
   evicted  : NodeInfo,
   inserted : NodeInfo
}

/// Bucket size is estimated to be small enough not to warrant
/// the downsides of using a linked list.
///
/// Each vector of bucket entries is protected under its own mutex, to guarantee
/// concurrent access to the table.
#[derive(Debug)]
struct Bucket {
   entries: RwLock<VecDeque<NodeInfo>>,
}

impl<'a, 'b> Iterator for ClosestNodesTo<'a, 'b> {
   type Item = NodeInfo;

   fn next(&mut self) -> Option<NodeInfo> {
      if !self.current_bucket.is_empty() {
         return self.current_bucket.pop();
      }

      while let Some(index) = self.lookup_order.next() {
         let mut new_bucket = { // Lock scope
            let bucket = self.table.buckets[index].entries.read().unwrap();
            if bucket.is_empty() {
               continue;
            }
            bucket.clone()
         }.into_iter().collect::<Vec<NodeInfo>>();

         new_bucket.sort_by(|ref info_a, ref info_b| (&info_b.id ^ &self.reference).cmp(&(&info_a.id ^ &self.reference)));
         self.current_bucket.append(&mut new_bucket);
         return self.current_bucket.pop();
      }
      None
   }
}

impl<'a> Iterator for AllNodes<'a> {
   type Item = NodeInfo;

   fn next(&mut self) -> Option<NodeInfo> {
      while self.bucket_index < HASH_SIZE && self.current_bucket.is_empty() {
         let mut new_bucket = { // Lock scope
            self.table.buckets[self.bucket_index].entries.read().unwrap().clone()
         }.into_iter().collect::<Vec<NodeInfo>>();

         new_bucket.sort_by_key(|ref info| &info.id ^ &self.table.parent_id);
         self.current_bucket.append(&mut new_bucket);
         self.bucket_index += 1;
      }
      self.current_bucket.pop()
   }
}

impl Bucket {
   fn new() -> Bucket {
      Bucket{
         entries: RwLock::new(VecDeque::with_capacity(BUCKET_DEPTH))
      }
   }
}
<commit_msg>Removed non-iterator lookup method<commit_after>use hash::HASH_SIZE;
use hash;
use hash::Hash;
use std::net;
use std::collections::VecDeque;
use std::mem;
use std::sync::{Mutex, RwLock};
use std::iter::{Chain, Rev};

#[cfg(test)]
mod tests;

/// System-wide concurrency factor. It's used, for example, to decide the
/// number of remote nodes to interrogate concurrently when performing a
/// network-wide lookup.
pub const ALPHA    : usize = 3;

/// Data structure factor. It's used, among other places, to dictate the
/// size of a K-bucket.
pub const K        : usize = 20;
const BUCKET_DEPTH : usize = K;

/// Routing table with 160 buckets of `BUCKET_DEPTH` (k) node
/// identifiers each, constructed around a parent node ID.
///
/// The structure employs least-recently seen eviction. Conflicts generated
/// by evicting a node by inserting a newer one remain tracked, so they can
/// be resolved later.
pub struct Table {
   buckets   : Vec<Bucket>,
   conflicts : Mutex<Vec<EvictionConflict>>,
   parent_id : Hash,
}

/// ID - Address pair that identifies a unique Subotai node in the network.
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct NodeInfo {
   pub id      : Hash,
   pub address : net::SocketAddr,
}

/// Result of a table lookup.
/// * `Myself`: The requested ID is precisely the parent node.
///
/// * `Found`: The requested ID was found on the table.
///
/// * `ClosestNodes`: The requested ID was not found, but here are the next
///   closest nodes to consult.
///
/// * `Nothing`: The table is empty or the blacklist provided doesn't allow
///   returning any close nodes.
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub enum LookupResult {
   Myself,
   Found(NodeInfo),
   ClosestNodes(Vec<NodeInfo>),
   Nothing,
}

impl Table {
   /// Constructs a routing table based on a parent node id. Other nodes
   /// will be stored in this table based on their distance to the node id provided.
   pub fn new(parent_id: Hash) -> Table {
      Table {
         buckets   : (0..HASH_SIZE).map(|_| Bucket::new()).collect(),
         conflicts : Mutex::new(Vec::new()),
         parent_id : parent_id,
      }
   }

   /// Returns the number of nodes currently on the table.
   pub fn len(&self) -> usize {
      self.buckets.iter().map(|bucket| bucket.entries.read().unwrap().len()).sum()
   }

   /// Inserts a node in the routing table. Employs least-recently-seen eviction
   /// by kicking out the oldest node in case the bucket is full, and registering
   /// an eviction conflict that can be revised later.
   pub fn insert_node(&self, info: NodeInfo) {
      if let Some(index) = self.bucket_for_node(&info.id) {
         let bucket = &self.buckets[index];
         let mut entries = bucket.entries.write().unwrap();

         entries.retain(|ref stored_info| info.id != stored_info.id);
         if entries.len() == BUCKET_DEPTH {
            let conflict = EvictionConflict {
               evicted  : entries.pop_front().unwrap(),
               inserted : info.clone()
            };
            let mut conflicts = self.conflicts.lock().unwrap();
            conflicts.push(conflict);
         }
         entries.push_back(info);
      }
   }

   /// Performs a node lookup on the routing table. The lookup result may
   /// contain the specific node, a list of up to the N closest nodes, or
   /// report that the parent node itself was requested.
   ///
   /// This employs an algorithm I have named "bounce lookup", which obtains
   /// the closest nodes to a given origin walking through the minimum
   /// amount of buckets. It may exist already, but I haven't
   /// found it any other implementation. It consists of:
   ///
   /// * Calculating the XOR distance between the parent node ID and the
   ///   lookup node ID.
   ///
   /// * Checking the buckets indexed by the position of every "1" in said
   ///   distance hash, in descending order.
   ///
   /// * "Bounce" back up, checking the buckets indexed by the position of
   ///   every "0" in that distance hash, in ascending order.
   pub fn lookup(&self, id: &Hash, n: usize, blacklist: Option<&Vec<Hash>>) -> LookupResult {
      if id == &self.parent_id {
         return LookupResult::Myself;
      }

      match self.specific_node(id) {
         Some(info) => LookupResult::Found(info),
         None =>  {
            let closest: Vec<NodeInfo> = self.closest_nodes_to(id)
               .take(n)
               .filter(|ref info| Self::is_allowed(&info.id, blacklist))
               .collect();

            if closest.is_empty() {
               LookupResult::Nothing
            } else {
               LookupResult::ClosestNodes(closest)
            }
         }
      }
   }

   fn is_allowed(id: &Hash, blacklist: Option<&Vec<Hash>>) -> bool {
      if let Some(blacklist) = blacklist {
         !blacklist.contains(id)
      } else {
         true
      }
   }

   /// Returns an iterator over all stored nodes, ordered by ascending
   /// distance to the parent node. This iterator is designed for concurrent
   /// access to the data structure, and as such it isn't guaranteed that it
   /// will return a "snapshot" of all nodes for a specific moment in time.
   /// Buckets already visited may be modified elsewhere through iteraton,
   /// and unvisited buckets may accrue new nodes.
   pub fn all_nodes(&self) -> AllNodes {
      AllNodes {
         table          : self,
         current_bucket : Vec::with_capacity(BUCKET_DEPTH),
         bucket_index   : 0,
      }
   }

   /// Returns an iterator over all stored nodes, ordered by ascending
   /// distance to a given reference ID. This iterator is designed for concurrent
   /// access to the data structure, and as such it isn't guaranteed that it
   /// will return a "snapshot" of all nodes for a specific moment in time.
   /// Buckets already visited may be modified elsewhere through iteraton,
   /// and unvisited buckets may accrue new nodes.
   pub fn closest_nodes_to<'a,'b>(&'a self, id: &'b Hash) -> ClosestNodesTo<'a,'b> {
      let distance = &self.parent_id ^ id;
      let descent  = distance.clone().into_ones().rev();
      let ascent   = distance.into_zeroes();
      let lookup_order = descent.chain(ascent);

      ClosestNodesTo {
         table          : self,
         reference      : id,
         lookup_order   : lookup_order,
         current_bucket : Vec::with_capacity(BUCKET_DEPTH),
      }
   }

   /// Returns a table entry for the specific node with a given hash.
   pub fn specific_node(&self, id: &Hash) -> Option<NodeInfo> {
      if let Some(index) = self.bucket_for_node(id) {
         let entries = &self.buckets[index].entries.read().unwrap();
         return entries.iter().find(|ref info| *id == info.id).cloned();
      }
      None
   }

   /// Returns the appropriate position for a node, by computing
   /// the index where their prefix starts differing. If we are requesting
   /// the bucket for this table's own parent node, it can't be stored.
   fn bucket_for_node(&self, id: &Hash) -> Option<usize> {
       (&self.parent_id ^ id).height()
   }

   fn revert_conflict(&self, conflict: EvictionConflict) {
      if let Some(index) = self.bucket_for_node(&conflict.inserted.id) {
         let mut entries = self.buckets[index].entries.write().unwrap();
         let evictor = &mut entries.iter_mut().find(|ref info| conflict.inserted.id == info.id).unwrap();
         mem::replace::<NodeInfo>(evictor, conflict.evicted);
      }
   }
}

/// Produces copies of all known nodes, ordered in ascending
/// distance from self. The table may be modified through iteration.
pub struct AllNodes<'a> {
   table          : &'a Table,
   current_bucket : Vec<NodeInfo>,
   bucket_index   : usize,
}

/// Produces copies of all known nodes, ordered in ascending
/// distance from a reference ID.
pub struct ClosestNodesTo<'a, 'b> {
   table          : &'a Table,
   reference      : &'b hash::Hash,
   lookup_order   : Chain<Rev<hash::IntoOnes>, hash::IntoZeroes>,
   current_bucket : Vec<NodeInfo>,
}

/// Represents a conflict derived from attempting to insert a node in a full
/// bucket.
#[derive(Debug,Clone)]
struct EvictionConflict {
   evicted  : NodeInfo,
   inserted : NodeInfo
}

/// Bucket size is estimated to be small enough not to warrant
/// the downsides of using a linked list.
///
/// Each vector of bucket entries is protected under its own mutex, to guarantee
/// concurrent access to the table.
#[derive(Debug)]
struct Bucket {
   entries: RwLock<VecDeque<NodeInfo>>,
}

impl<'a, 'b> Iterator for ClosestNodesTo<'a, 'b> {
   type Item = NodeInfo;

   fn next(&mut self) -> Option<NodeInfo> {
      if !self.current_bucket.is_empty() {
         return self.current_bucket.pop();
      }

      while let Some(index) = self.lookup_order.next() {
         let mut new_bucket = { // Lock scope
            let bucket = self.table.buckets[index].entries.read().unwrap();
            if bucket.is_empty() {
               continue;
            }
            bucket.clone()
         }.into_iter().collect::<Vec<NodeInfo>>();

         new_bucket.sort_by(|ref info_a, ref info_b| (&info_b.id ^ &self.reference).cmp(&(&info_a.id ^ &self.reference)));
         self.current_bucket.append(&mut new_bucket);
         return self.current_bucket.pop();
      }
      None
   }
}

impl<'a> Iterator for AllNodes<'a> {
   type Item = NodeInfo;

   fn next(&mut self) -> Option<NodeInfo> {
      while self.bucket_index < HASH_SIZE && self.current_bucket.is_empty() {
         let mut new_bucket = { // Lock scope
            self.table.buckets[self.bucket_index].entries.read().unwrap().clone()
         }.into_iter().collect::<Vec<NodeInfo>>();

         new_bucket.sort_by_key(|ref info| &info.id ^ &self.table.parent_id);
         self.current_bucket.append(&mut new_bucket);
         self.bucket_index += 1;
      }
      self.current_bucket.pop()
   }
}

impl Bucket {
   fn new() -> Bucket {
      Bucket{
         entries: RwLock::new(VecDeque::with_capacity(BUCKET_DEPTH))
      }
   }
}
<|endoftext|>


<commit_before>// Copyright 2016 TiKV Project Authors. Licensed under Apache-2.0.

use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

use super::RaftKv;
use super::Result;
use crate::import::SSTImporter;
use crate::read_pool::ReadPoolHandle;
use crate::server::lock_manager::LockManager;
use crate::server::Config as ServerConfig;
use crate::storage::{config::Config as StorageConfig, Storage};
use engine_rocks::{RocksEngine, RocksSnapshot};
use engine_traits::{KvEngines, Peekable};
use kvproto::metapb;
use kvproto::raft_serverpb::StoreIdent;
use kvproto::replication_modepb::ReplicationStatus;
use pd_client::{Error as PdError, PdClient, INVALID_ID};
use raftstore::coprocessor::dispatcher::CoprocessorHost;
use raftstore::router::RaftStoreRouter;
use raftstore::store::fsm::store::StoreMeta;
use raftstore::store::fsm::{ApplyRouter, RaftBatchSystem, RaftRouter};
use raftstore::store::AutoSplitController;
use raftstore::store::{self, initial_region, Config as StoreConfig, SnapManager, Transport};
use raftstore::store::{GlobalReplicationState, PdTask, SplitCheckTask};
use tikv_util::config::VersionTrack;
use tikv_util::worker::FutureWorker;
use tikv_util::worker::Worker;

const MAX_CHECK_CLUSTER_BOOTSTRAPPED_RETRY_COUNT: u64 = 60;
const CHECK_CLUSTER_BOOTSTRAPPED_RETRY_SECONDS: u64 = 3;

/// Creates a new storage engine which is backed by the Raft consensus
/// protocol.
pub fn create_raft_storage<S>(
    engine: RaftKv<S>,
    cfg: &StorageConfig,
    read_pool: ReadPoolHandle,
    lock_mgr: LockManager,
    pipelined_pessimistic_lock: bool,
) -> Result<Storage<RaftKv<S>, LockManager>>
where
    S: RaftStoreRouter<RocksSnapshot> + 'static,
{
    let store = Storage::from_engine(engine, cfg, read_pool, lock_mgr, pipelined_pessimistic_lock)?;
    Ok(store)
}

/// A wrapper for the raftstore which runs Multi-Raft.
// TODO: we will rename another better name like RaftStore later.
pub struct Node<C: PdClient + 'static> {
    cluster_id: u64,
    store: metapb::Store,
    store_cfg: Arc<VersionTrack<StoreConfig>>,
    system: RaftBatchSystem,
    has_started: bool,

    pd_client: Arc<C>,
    state: Arc<Mutex<GlobalReplicationState>>,
}

impl<C> Node<C>
where
    C: PdClient,
{
    /// Creates a new Node.
    pub fn new(
        system: RaftBatchSystem,
        cfg: &ServerConfig,
        store_cfg: Arc<VersionTrack<StoreConfig>>,
        pd_client: Arc<C>,
        state: Arc<Mutex<GlobalReplicationState>>,
    ) -> Node<C> {
        let mut store = metapb::Store::default();
        store.set_id(INVALID_ID);
        if cfg.advertise_addr.is_empty() {
            store.set_address(cfg.addr.clone());
        } else {
            store.set_address(cfg.advertise_addr.clone())
        }
        if cfg.advertise_status_addr.is_empty() {
            store.set_status_address(cfg.status_addr.clone());
        } else {
            store.set_status_address(cfg.advertise_status_addr.clone())
        }
        store.set_version(env!("CARGO_PKG_VERSION").to_string());

        if let Ok(path) = std::env::current_exe() {
            if let Some(path) = path.parent() {
                store.set_deploy_path(path.to_string_lossy().to_string());
            }
        };

        store.set_start_timestamp(chrono::Local::now().timestamp());
        store.set_git_hash(
            option_env!("TIKV_BUILD_GIT_HASH")
                .unwrap_or("Unknown git hash")
                .to_string(),
        );

        let mut labels = Vec::new();
        for (k, v) in &cfg.labels {
            let mut label = metapb::StoreLabel::default();
            label.set_key(k.to_owned());
            label.set_value(v.to_owned());
            labels.push(label);
        }
        store.set_labels(labels.into());

        Node {
            cluster_id: cfg.cluster_id,
            store,
            store_cfg,
            pd_client,
            system,
            has_started: false,
            state,
        }
    }

    /// Starts the Node. It tries to bootstrap cluster if the cluster is not
    /// bootstrapped yet. Then it spawns a thread to run the raftstore in
    /// background.
    #[allow(clippy::too_many_arguments)]
    pub fn start<T>(
        &mut self,
        engines: KvEngines<RocksEngine, RocksEngine>,
        trans: T,
        snap_mgr: SnapManager<RocksEngine>,
        pd_worker: FutureWorker<PdTask<RocksEngine>>,
        store_meta: Arc<Mutex<StoreMeta>>,
        coprocessor_host: CoprocessorHost<RocksEngine>,
        importer: Arc<SSTImporter>,
        split_check_worker: Worker<SplitCheckTask>,
        auto_split_controller: AutoSplitController,
    ) -> Result<()>
    where
        T: Transport + 'static,
    {
        let mut store_id = self.check_store(&engines)?;
        if store_id == INVALID_ID {
            store_id = self.bootstrap_store(&engines)?;
            fail_point!("node_after_bootstrap_store", |_| Err(box_err!(
                "injected error: node_after_bootstrap_store"
            )));
        }
        self.store.set_id(store_id);
        {
            let mut meta = store_meta.lock().unwrap();
            meta.store_id = Some(store_id);
        }
        if let Some(first_region) = self.check_or_prepare_bootstrap_cluster(&engines, store_id)? {
            info!("trying to bootstrap cluster"; "store_id" => store_id, "region" => ?first_region);
            // cluster is not bootstrapped, and we choose first store to bootstrap
            fail_point!("node_after_prepare_bootstrap_cluster", |_| Err(box_err!(
                "injected error: node_after_prepare_bootstrap_cluster"
            )));
            self.bootstrap_cluster(&engines, first_region)?;
        }

        // Put store only if the cluster is bootstrapped.
        info!("put store to PD"; "store" => ?&self.store);
        let status = self.pd_client.put_store(self.store.clone())?;
        self.load_all_stores(status);

        self.start_store(
            store_id,
            engines,
            trans,
            snap_mgr,
            pd_worker,
            store_meta,
            coprocessor_host,
            importer,
            split_check_worker,
            auto_split_controller,
        )?;

        Ok(())
    }

    /// Gets the store id.
    pub fn id(&self) -> u64 {
        self.store.get_id()
    }

    /// Gets a transmission end of a channel which is used to send `Msg` to the
    /// raftstore.
    pub fn get_router(&self) -> RaftRouter<RocksSnapshot> {
        self.system.router()
    }
    /// Gets a transmission end of a channel which is used send messages to apply worker.
    pub fn get_apply_router(&self) -> ApplyRouter {
        self.system.apply_router()
    }

    // check store, return store id for the engine.
    // If the store is not bootstrapped, use INVALID_ID.
    fn check_store(&self, engines: &KvEngines<RocksEngine, RocksEngine>) -> Result<u64> {
        let res = engines.kv.get_msg::<StoreIdent>(keys::STORE_IDENT_KEY)?;
        if res.is_none() {
            return Ok(INVALID_ID);
        }

        let ident = res.unwrap();
        if ident.get_cluster_id() != self.cluster_id {
            return Err(box_err!(
                "cluster ID mismatch, local {} != remote {}, \
                 you are trying to connect to another cluster, please reconnect to the correct PD",
                ident.get_cluster_id(),
                self.cluster_id
            ));
        }

        let store_id = ident.get_store_id();
        if store_id == INVALID_ID {
            return Err(box_err!("invalid store ident {:?}", ident));
        }
        Ok(store_id)
    }

    fn alloc_id(&self) -> Result<u64> {
        let id = self.pd_client.alloc_id()?;
        Ok(id)
    }

    fn load_all_stores(&mut self, status: Option<ReplicationStatus>) {
        info!("initializing replication mode"; "status" => ?status, "store_id" => self.store.id);
        let stores = match self.pd_client.get_all_stores(false) {
            Ok(stores) => stores,
            Err(e) => panic!("failed to load all stores: {:?}", e),
        };
        let mut state = self.state.lock().unwrap();
        if let Some(s) = status {
            state.set_status(s);
        }
        for mut store in stores {
            state
                .group
                .register_store(store.id, store.take_labels().into());
        }
    }

    fn bootstrap_store(&self, engines: &KvEngines<RocksEngine, RocksEngine>) -> Result<u64> {
        let store_id = self.alloc_id()?;
        debug!("alloc store id"; "store_id" => store_id);

        store::bootstrap_store(&engines, self.cluster_id, store_id)?;

        Ok(store_id)
    }

    // Exported for tests.
    #[doc(hidden)]
    pub fn prepare_bootstrap_cluster(
        &self,
        engines: &KvEngines<RocksEngine, RocksEngine>,
        store_id: u64,
    ) -> Result<metapb::Region> {
        let region_id = self.alloc_id()?;
        debug!(
            "alloc first region id";
            "region_id" => region_id,
            "cluster_id" => self.cluster_id,
            "store_id" => store_id
        );
        let peer_id = self.alloc_id()?;
        debug!(
            "alloc first peer id for first region";
            "peer_id" => peer_id,
            "region_id" => region_id,
        );

        let region = initial_region(store_id, region_id, peer_id);
        store::prepare_bootstrap_cluster(&engines, &region)?;
        Ok(region)
    }

    fn check_or_prepare_bootstrap_cluster(
        &self,
        engines: &KvEngines<RocksEngine, RocksEngine>,
        store_id: u64,
    ) -> Result<Option<metapb::Region>> {
        if let Some(first_region) = engines.kv.get_msg(keys::PREPARE_BOOTSTRAP_KEY)? {
            Ok(Some(first_region))
        } else {
            if self.check_cluster_bootstrapped()? {
                Ok(None)
            } else {
                self.prepare_bootstrap_cluster(engines, store_id).map(Some)
            }
        }
    }

    fn bootstrap_cluster(
        &mut self,
        engines: &KvEngines<RocksEngine, RocksEngine>,
        first_region: metapb::Region,
    ) -> Result<()> {
        let region_id = first_region.get_id();
        let mut retry = 0;
        while retry < MAX_CHECK_CLUSTER_BOOTSTRAPPED_RETRY_COUNT {
            match self
                .pd_client
                .bootstrap_cluster(self.store.clone(), first_region.clone())
            {
                Ok(_) => {
                    info!("bootstrap cluster ok"; "cluster_id" => self.cluster_id);
                    fail_point!("node_after_bootstrap_cluster", |_| Err(box_err!(
                        "injected error: node_after_prepare_bootstrap_cluster"
                    )));
                    store::clear_prepare_bootstrap_key(&engines)?;
                    return Ok(());
                }
                Err(PdError::ClusterBootstrapped(_)) => match self.pd_client.get_region(b"") {
                    Ok(region) => {
                        if region == first_region {
                            store::clear_prepare_bootstrap_key(&engines)?;
                            return Ok(());
                        } else {
                            info!("cluster is already bootstrapped"; "cluster_id" => self.cluster_id);
                            store::clear_prepare_bootstrap_cluster(&engines, region_id)?;
                            return Ok(());
                        }
                    }
                    Err(e) => {
                        warn!("get the first region failed"; "err" => ?e);
                    }
                },
                // TODO: should we clean region for other errors too?
                Err(e) => {
                    error!("bootstrap cluster"; "cluster_id" => self.cluster_id, "error" => ?e)
                }
            }
            retry += 1;
            thread::sleep(Duration::from_secs(
                CHECK_CLUSTER_BOOTSTRAPPED_RETRY_SECONDS,
            ));
        }
        Err(box_err!("bootstrapped cluster failed"))
    }

    fn check_cluster_bootstrapped(&self) -> Result<bool> {
        for _ in 0..MAX_CHECK_CLUSTER_BOOTSTRAPPED_RETRY_COUNT {
            match self.pd_client.is_cluster_bootstrapped() {
                Ok(b) => return Ok(b),
                Err(e) => {
                    warn!("check cluster bootstrapped failed"; "err" => ?e);
                }
            }
            thread::sleep(Duration::from_secs(
                CHECK_CLUSTER_BOOTSTRAPPED_RETRY_SECONDS,
            ));
        }
        Err(box_err!("check cluster bootstrapped failed"))
    }

    #[allow(clippy::too_many_arguments)]
    fn start_store<T>(
        &mut self,
        store_id: u64,
        engines: KvEngines<RocksEngine, RocksEngine>,
        trans: T,
        snap_mgr: SnapManager<RocksEngine>,
        pd_worker: FutureWorker<PdTask<RocksEngine>>,
        store_meta: Arc<Mutex<StoreMeta>>,
        coprocessor_host: CoprocessorHost<RocksEngine>,
        importer: Arc<SSTImporter>,
        split_check_worker: Worker<SplitCheckTask>,
        auto_split_controller: AutoSplitController,
    ) -> Result<()>
    where
        T: Transport + 'static,
    {
        info!("start raft store thread"; "store_id" => store_id);

        if self.has_started {
            return Err(box_err!("{} is already started", store_id));
        }
        self.has_started = true;
        let cfg = self.store_cfg.clone();
        let pd_client = Arc::clone(&self.pd_client);
        let store = self.store.clone();
        self.system.spawn(
            store,
            cfg,
            engines,
            trans,
            pd_client,
            snap_mgr,
            pd_worker,
            store_meta,
            coprocessor_host,
            importer,
            split_check_worker,
            auto_split_controller,
            self.state.clone(),
        )?;
        Ok(())
    }

    fn stop_store(&mut self, store_id: u64) {
        info!("stop raft store thread"; "store_id" => store_id);
        self.system.shutdown();
    }

    /// Stops the Node.
    pub fn stop(&mut self) {
        let store_id = self.store.get_id();
        self.stop_store(store_id)
    }
}
<commit_msg>Fix box error name in bootstrap_cluster (#8245)<commit_after>// Copyright 2016 TiKV Project Authors. Licensed under Apache-2.0.

use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

use super::RaftKv;
use super::Result;
use crate::import::SSTImporter;
use crate::read_pool::ReadPoolHandle;
use crate::server::lock_manager::LockManager;
use crate::server::Config as ServerConfig;
use crate::storage::{config::Config as StorageConfig, Storage};
use engine_rocks::{RocksEngine, RocksSnapshot};
use engine_traits::{KvEngines, Peekable};
use kvproto::metapb;
use kvproto::raft_serverpb::StoreIdent;
use kvproto::replication_modepb::ReplicationStatus;
use pd_client::{Error as PdError, PdClient, INVALID_ID};
use raftstore::coprocessor::dispatcher::CoprocessorHost;
use raftstore::router::RaftStoreRouter;
use raftstore::store::fsm::store::StoreMeta;
use raftstore::store::fsm::{ApplyRouter, RaftBatchSystem, RaftRouter};
use raftstore::store::AutoSplitController;
use raftstore::store::{self, initial_region, Config as StoreConfig, SnapManager, Transport};
use raftstore::store::{GlobalReplicationState, PdTask, SplitCheckTask};
use tikv_util::config::VersionTrack;
use tikv_util::worker::FutureWorker;
use tikv_util::worker::Worker;

const MAX_CHECK_CLUSTER_BOOTSTRAPPED_RETRY_COUNT: u64 = 60;
const CHECK_CLUSTER_BOOTSTRAPPED_RETRY_SECONDS: u64 = 3;

/// Creates a new storage engine which is backed by the Raft consensus
/// protocol.
pub fn create_raft_storage<S>(
    engine: RaftKv<S>,
    cfg: &StorageConfig,
    read_pool: ReadPoolHandle,
    lock_mgr: LockManager,
    pipelined_pessimistic_lock: bool,
) -> Result<Storage<RaftKv<S>, LockManager>>
where
    S: RaftStoreRouter<RocksSnapshot> + 'static,
{
    let store = Storage::from_engine(engine, cfg, read_pool, lock_mgr, pipelined_pessimistic_lock)?;
    Ok(store)
}

/// A wrapper for the raftstore which runs Multi-Raft.
// TODO: we will rename another better name like RaftStore later.
pub struct Node<C: PdClient + 'static> {
    cluster_id: u64,
    store: metapb::Store,
    store_cfg: Arc<VersionTrack<StoreConfig>>,
    system: RaftBatchSystem,
    has_started: bool,

    pd_client: Arc<C>,
    state: Arc<Mutex<GlobalReplicationState>>,
}

impl<C> Node<C>
where
    C: PdClient,
{
    /// Creates a new Node.
    pub fn new(
        system: RaftBatchSystem,
        cfg: &ServerConfig,
        store_cfg: Arc<VersionTrack<StoreConfig>>,
        pd_client: Arc<C>,
        state: Arc<Mutex<GlobalReplicationState>>,
    ) -> Node<C> {
        let mut store = metapb::Store::default();
        store.set_id(INVALID_ID);
        if cfg.advertise_addr.is_empty() {
            store.set_address(cfg.addr.clone());
        } else {
            store.set_address(cfg.advertise_addr.clone())
        }
        if cfg.advertise_status_addr.is_empty() {
            store.set_status_address(cfg.status_addr.clone());
        } else {
            store.set_status_address(cfg.advertise_status_addr.clone())
        }
        store.set_version(env!("CARGO_PKG_VERSION").to_string());

        if let Ok(path) = std::env::current_exe() {
            if let Some(path) = path.parent() {
                store.set_deploy_path(path.to_string_lossy().to_string());
            }
        };

        store.set_start_timestamp(chrono::Local::now().timestamp());
        store.set_git_hash(
            option_env!("TIKV_BUILD_GIT_HASH")
                .unwrap_or("Unknown git hash")
                .to_string(),
        );

        let mut labels = Vec::new();
        for (k, v) in &cfg.labels {
            let mut label = metapb::StoreLabel::default();
            label.set_key(k.to_owned());
            label.set_value(v.to_owned());
            labels.push(label);
        }
        store.set_labels(labels.into());

        Node {
            cluster_id: cfg.cluster_id,
            store,
            store_cfg,
            pd_client,
            system,
            has_started: false,
            state,
        }
    }

    /// Starts the Node. It tries to bootstrap cluster if the cluster is not
    /// bootstrapped yet. Then it spawns a thread to run the raftstore in
    /// background.
    #[allow(clippy::too_many_arguments)]
    pub fn start<T>(
        &mut self,
        engines: KvEngines<RocksEngine, RocksEngine>,
        trans: T,
        snap_mgr: SnapManager<RocksEngine>,
        pd_worker: FutureWorker<PdTask<RocksEngine>>,
        store_meta: Arc<Mutex<StoreMeta>>,
        coprocessor_host: CoprocessorHost<RocksEngine>,
        importer: Arc<SSTImporter>,
        split_check_worker: Worker<SplitCheckTask>,
        auto_split_controller: AutoSplitController,
    ) -> Result<()>
    where
        T: Transport + 'static,
    {
        let mut store_id = self.check_store(&engines)?;
        if store_id == INVALID_ID {
            store_id = self.bootstrap_store(&engines)?;
            fail_point!("node_after_bootstrap_store", |_| Err(box_err!(
                "injected error: node_after_bootstrap_store"
            )));
        }
        self.store.set_id(store_id);
        {
            let mut meta = store_meta.lock().unwrap();
            meta.store_id = Some(store_id);
        }
        if let Some(first_region) = self.check_or_prepare_bootstrap_cluster(&engines, store_id)? {
            info!("trying to bootstrap cluster"; "store_id" => store_id, "region" => ?first_region);
            // cluster is not bootstrapped, and we choose first store to bootstrap
            fail_point!("node_after_prepare_bootstrap_cluster", |_| Err(box_err!(
                "injected error: node_after_prepare_bootstrap_cluster"
            )));
            self.bootstrap_cluster(&engines, first_region)?;
        }

        // Put store only if the cluster is bootstrapped.
        info!("put store to PD"; "store" => ?&self.store);
        let status = self.pd_client.put_store(self.store.clone())?;
        self.load_all_stores(status);

        self.start_store(
            store_id,
            engines,
            trans,
            snap_mgr,
            pd_worker,
            store_meta,
            coprocessor_host,
            importer,
            split_check_worker,
            auto_split_controller,
        )?;

        Ok(())
    }

    /// Gets the store id.
    pub fn id(&self) -> u64 {
        self.store.get_id()
    }

    /// Gets a transmission end of a channel which is used to send `Msg` to the
    /// raftstore.
    pub fn get_router(&self) -> RaftRouter<RocksSnapshot> {
        self.system.router()
    }
    /// Gets a transmission end of a channel which is used send messages to apply worker.
    pub fn get_apply_router(&self) -> ApplyRouter {
        self.system.apply_router()
    }

    // check store, return store id for the engine.
    // If the store is not bootstrapped, use INVALID_ID.
    fn check_store(&self, engines: &KvEngines<RocksEngine, RocksEngine>) -> Result<u64> {
        let res = engines.kv.get_msg::<StoreIdent>(keys::STORE_IDENT_KEY)?;
        if res.is_none() {
            return Ok(INVALID_ID);
        }

        let ident = res.unwrap();
        if ident.get_cluster_id() != self.cluster_id {
            return Err(box_err!(
                "cluster ID mismatch, local {} != remote {}, \
                 you are trying to connect to another cluster, please reconnect to the correct PD",
                ident.get_cluster_id(),
                self.cluster_id
            ));
        }

        let store_id = ident.get_store_id();
        if store_id == INVALID_ID {
            return Err(box_err!("invalid store ident {:?}", ident));
        }
        Ok(store_id)
    }

    fn alloc_id(&self) -> Result<u64> {
        let id = self.pd_client.alloc_id()?;
        Ok(id)
    }

    fn load_all_stores(&mut self, status: Option<ReplicationStatus>) {
        info!("initializing replication mode"; "status" => ?status, "store_id" => self.store.id);
        let stores = match self.pd_client.get_all_stores(false) {
            Ok(stores) => stores,
            Err(e) => panic!("failed to load all stores: {:?}", e),
        };
        let mut state = self.state.lock().unwrap();
        if let Some(s) = status {
            state.set_status(s);
        }
        for mut store in stores {
            state
                .group
                .register_store(store.id, store.take_labels().into());
        }
    }

    fn bootstrap_store(&self, engines: &KvEngines<RocksEngine, RocksEngine>) -> Result<u64> {
        let store_id = self.alloc_id()?;
        debug!("alloc store id"; "store_id" => store_id);

        store::bootstrap_store(&engines, self.cluster_id, store_id)?;

        Ok(store_id)
    }

    // Exported for tests.
    #[doc(hidden)]
    pub fn prepare_bootstrap_cluster(
        &self,
        engines: &KvEngines<RocksEngine, RocksEngine>,
        store_id: u64,
    ) -> Result<metapb::Region> {
        let region_id = self.alloc_id()?;
        debug!(
            "alloc first region id";
            "region_id" => region_id,
            "cluster_id" => self.cluster_id,
            "store_id" => store_id
        );
        let peer_id = self.alloc_id()?;
        debug!(
            "alloc first peer id for first region";
            "peer_id" => peer_id,
            "region_id" => region_id,
        );

        let region = initial_region(store_id, region_id, peer_id);
        store::prepare_bootstrap_cluster(&engines, &region)?;
        Ok(region)
    }

    fn check_or_prepare_bootstrap_cluster(
        &self,
        engines: &KvEngines<RocksEngine, RocksEngine>,
        store_id: u64,
    ) -> Result<Option<metapb::Region>> {
        if let Some(first_region) = engines.kv.get_msg(keys::PREPARE_BOOTSTRAP_KEY)? {
            Ok(Some(first_region))
        } else {
            if self.check_cluster_bootstrapped()? {
                Ok(None)
            } else {
                self.prepare_bootstrap_cluster(engines, store_id).map(Some)
            }
        }
    }

    fn bootstrap_cluster(
        &mut self,
        engines: &KvEngines<RocksEngine, RocksEngine>,
        first_region: metapb::Region,
    ) -> Result<()> {
        let region_id = first_region.get_id();
        let mut retry = 0;
        while retry < MAX_CHECK_CLUSTER_BOOTSTRAPPED_RETRY_COUNT {
            match self
                .pd_client
                .bootstrap_cluster(self.store.clone(), first_region.clone())
            {
                Ok(_) => {
                    info!("bootstrap cluster ok"; "cluster_id" => self.cluster_id);
                    fail_point!("node_after_bootstrap_cluster", |_| Err(box_err!(
                        "injected error: node_after_bootstrap_cluster"
                    )));
                    store::clear_prepare_bootstrap_key(&engines)?;
                    return Ok(());
                }
                Err(PdError::ClusterBootstrapped(_)) => match self.pd_client.get_region(b"") {
                    Ok(region) => {
                        if region == first_region {
                            store::clear_prepare_bootstrap_key(&engines)?;
                            return Ok(());
                        } else {
                            info!("cluster is already bootstrapped"; "cluster_id" => self.cluster_id);
                            store::clear_prepare_bootstrap_cluster(&engines, region_id)?;
                            return Ok(());
                        }
                    }
                    Err(e) => {
                        warn!("get the first region failed"; "err" => ?e);
                    }
                },
                // TODO: should we clean region for other errors too?
                Err(e) => {
                    error!("bootstrap cluster"; "cluster_id" => self.cluster_id, "error" => ?e)
                }
            }
            retry += 1;
            thread::sleep(Duration::from_secs(
                CHECK_CLUSTER_BOOTSTRAPPED_RETRY_SECONDS,
            ));
        }
        Err(box_err!("bootstrapped cluster failed"))
    }

    fn check_cluster_bootstrapped(&self) -> Result<bool> {
        for _ in 0..MAX_CHECK_CLUSTER_BOOTSTRAPPED_RETRY_COUNT {
            match self.pd_client.is_cluster_bootstrapped() {
                Ok(b) => return Ok(b),
                Err(e) => {
                    warn!("check cluster bootstrapped failed"; "err" => ?e);
                }
            }
            thread::sleep(Duration::from_secs(
                CHECK_CLUSTER_BOOTSTRAPPED_RETRY_SECONDS,
            ));
        }
        Err(box_err!("check cluster bootstrapped failed"))
    }

    #[allow(clippy::too_many_arguments)]
    fn start_store<T>(
        &mut self,
        store_id: u64,
        engines: KvEngines<RocksEngine, RocksEngine>,
        trans: T,
        snap_mgr: SnapManager<RocksEngine>,
        pd_worker: FutureWorker<PdTask<RocksEngine>>,
        store_meta: Arc<Mutex<StoreMeta>>,
        coprocessor_host: CoprocessorHost<RocksEngine>,
        importer: Arc<SSTImporter>,
        split_check_worker: Worker<SplitCheckTask>,
        auto_split_controller: AutoSplitController,
    ) -> Result<()>
    where
        T: Transport + 'static,
    {
        info!("start raft store thread"; "store_id" => store_id);

        if self.has_started {
            return Err(box_err!("{} is already started", store_id));
        }
        self.has_started = true;
        let cfg = self.store_cfg.clone();
        let pd_client = Arc::clone(&self.pd_client);
        let store = self.store.clone();
        self.system.spawn(
            store,
            cfg,
            engines,
            trans,
            pd_client,
            snap_mgr,
            pd_worker,
            store_meta,
            coprocessor_host,
            importer,
            split_check_worker,
            auto_split_controller,
            self.state.clone(),
        )?;
        Ok(())
    }

    fn stop_store(&mut self, store_id: u64) {
        info!("stop raft store thread"; "store_id" => store_id);
        self.system.shutdown();
    }

    /// Stops the Node.
    pub fn stop(&mut self) {
        let store_id = self.store.get_id();
        self.stop_store(store_id)
    }
}
<|endoftext|>


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

use super::*;
use std::libc::{c_char, c_void};

pub type SF_MODE = i32;
pub static SFM_READ : SF_MODE   = 0x10;
pub static SFM_WRITE : SF_MODE  = 0x20;
pub static SFM_RDWR : SF_MODE   = 0x30;

pub type SF_ERR = i32;
pub static SF_ERR_NO_ERROR : SF_ERR             = 0;
pub static SF_ERR_UNRECOGNISED_FORMAT : SF_ERR  = 1;
pub static SF_ERR_SYSTEM : SF_ERR               = 2;
pub static SF_ERR_MALFORMED_FILE : SF_ERR       = 3;
pub static SF_ERR_UNSUPPORTED_ENCODING : SF_ERR = 4;

pub type SF_STR = i32;
pub static SF_STR_TITLE : SF_STR        = 0x01;
pub static SF_STR_COPYRIGHT : SF_STR    = 0x02;
pub static SF_STR_SOFTWARE : SF_STR     = 0x03;
pub static SF_STR_ARTIST : SF_STR       = 0x04;
pub static SF_STR_COMMENT : SF_STR      = 0x05;
pub static SF_STR_DATE : SF_STR         = 0x06;
pub static SF_STR_ALBUM : SF_STR        = 0x07;
pub static SF_STR_LICENSE : SF_STR      = 0x08;
pub static SF_STR_TRACKNUMBER : SF_STR  = 0x09;
pub static SF_STR_GENRE : SF_STR        = 0x10;

pub type SF_BOOL = i32;
pub static SF_FALSE : SF_BOOL   = 0;
pub static SF_TRUE : SF_BOOL    = 1;

pub type SEEK_MODE = i32;
pub static SEEK_SET : SEEK_MODE = 0;
pub static SEEK_CUR : SEEK_MODE = 1;
pub static SEEK_END : SEEK_MODE = 2;

pub type FORMAT_TYPE = i32;
pub static SF_FORMAT_WAV : FORMAT_TYPE          = 0x010000;   // Microsoft WAV format (little endian)
pub static SF_FORMAT_AIFF : FORMAT_TYPE         = 0x020000;   // Apple/SGI AIFF format (big endian)
pub static SF_FORMAT_AU : FORMAT_TYPE           = 0x030000;   // Sun/NeXT AU format (big endian)
pub static SF_FORMAT_RAW : FORMAT_TYPE          = 0x040000;   // RAW PCM data
pub static SF_FORMAT_PAF : FORMAT_TYPE          = 0x050000;   // Ensoniq PARIS file format
pub static SF_FORMAT_SVX : FORMAT_TYPE          = 0x060000;   // Amiga IFF / SVX8 / SV16 format
pub static SF_FORMAT_NIST : FORMAT_TYPE         = 0x070000;   // Sphere NIST format
pub static SF_FORMAT_VOC : FORMAT_TYPE          = 0x080000;   // VOC files
pub static SF_FORMAT_IRCAM : FORMAT_TYPE        = 0x0A0000;   // Berkeley/IRCAM/CARL
pub static SF_FORMAT_W64 : FORMAT_TYPE          = 0x0B0000;   // Sonic Foundry's 64 bit RIFF/WAV
pub static SF_FORMAT_MAT4 : FORMAT_TYPE         = 0x0C0000;   // Matlab (tm) V4.2 / GNU Octave 2.0
pub static SF_FORMAT_MAT5 : FORMAT_TYPE         = 0x0D0000;   // Matlab (tm) V5.0 / GNU Octave 2.1
pub static SF_FORMAT_PVF : FORMAT_TYPE          = 0x0E0000;   // Portable Voice Format
pub static SF_FORMAT_XI : FORMAT_TYPE           = 0x0F0000;   // Fasttracker 2 Extended Instrument
pub static SF_FORMAT_HTK : FORMAT_TYPE          = 0x100000;   // HMM Tool Kit format
pub static SF_FORMAT_SDS : FORMAT_TYPE          = 0x110000;   // Midi Sample Dump Standard
pub static SF_FORMAT_AVR : FORMAT_TYPE          = 0x120000;   // Audio Visual Research
pub static SF_FORMAT_WAVEX : FORMAT_TYPE        = 0x130000;   // MS WAVE with WAVEFORMATEX
pub static SF_FORMAT_SD2 : FORMAT_TYPE          = 0x160000;   // Sound Designer 2
pub static SF_FORMAT_FLAC : FORMAT_TYPE         = 0x170000;   // FLAC lossless file format
pub static SF_FORMAT_CAF : FORMAT_TYPE          = 0x180000;   // Core Audio File format
pub static SF_FORMAT_WVE : FORMAT_TYPE          = 0x190000;   // Psion WVE format
pub static SF_FORMAT_OGG : FORMAT_TYPE          = 0x200000;   // Xiph OGG container
pub static SF_FORMAT_MPC2K : FORMAT_TYPE        = 0x210000;   // Akai MPC 2000 sampler
pub static SF_FORMAT_RF64 : FORMAT_TYPE         = 0x220000;   // RF64 WAV file
/* Subtypes from here on. */
pub static SF_FORMAT_PCM_S8 : FORMAT_TYPE       = 0x0001;     // Signed 8 bit data
pub static SF_FORMAT_PCM_16 : FORMAT_TYPE       = 0x0002;     // Signed 16 bit data
pub static SF_FORMAT_PCM_24 : FORMAT_TYPE       = 0x0003;     // Signed 24 bit data
pub static SF_FORMAT_PCM_32 : FORMAT_TYPE       = 0x0004;     // Signed 32 bit data
pub static SF_FORMAT_PCM_U8 : FORMAT_TYPE       = 0x0005;     // Unsigned 8 bit data (WAV and RAW only)
pub static SF_FORMAT_FLOAT : FORMAT_TYPE        = 0x0006;     // 32 bit float data
pub static SF_FORMAT_DOUBLE : FORMAT_TYPE       = 0x0007;     // 64 bit float data
pub static SF_FORMAT_ULAW : FORMAT_TYPE         = 0x0010;     // U-Law encoded
pub static SF_FORMAT_ALAW : FORMAT_TYPE         = 0x0011;     // A-Law encoded
pub static SF_FORMAT_IMA_ADPCM : FORMAT_TYPE    = 0x0012;     // IMA ADPCM
pub static SF_FORMAT_MS_ADPCM : FORMAT_TYPE     = 0x0013;     // Microsoft ADPCM
pub static SF_FORMAT_GSM610 : FORMAT_TYPE       = 0x0020;     // GSM 6.10 encoding
pub static SF_FORMAT_VOX_ADPCM : FORMAT_TYPE    = 0x0021;     // Oki Dialogic ADPCM encoding
pub static SF_FORMAT_G721_32 : FORMAT_TYPE      = 0x0030;     // 32kbs G721 ADPCM encoding
pub static SF_FORMAT_G723_24 : FORMAT_TYPE      = 0x0031;     // 24kbs G723 ADPCM encoding
pub static SF_FORMAT_G723_40 : FORMAT_TYPE      = 0x0032;     // 40kbs G723 ADPCM encoding
pub static SF_FORMAT_DWVW_12 : FORMAT_TYPE      = 0x0040;     // 12 bit Delta Width Variable Word encoding
pub static SF_FORMAT_DWVW_16 : FORMAT_TYPE      = 0x0041;     // 16 bit Delta Width Variable Word encoding
pub static SF_FORMAT_DWVW_24 : FORMAT_TYPE      = 0x0042;     // 24 bit Delta Width Variable Word encoding
pub static SF_FORMAT_DWVW_N : FORMAT_TYPE       = 0x0043;     // N bit Delta Width Variable Word encoding
pub static SF_FORMAT_DPCM_8 : FORMAT_TYPE       = 0x0050;     // 8 bit differential PCM (XI only)
pub static SF_FORMAT_DPCM_16 : FORMAT_TYPE      = 0x0051;     // 16 bit differential PCM (XI only)
pub static SF_FORMAT_VORBIS : FORMAT_TYPE       = 0x0060;     // Xiph Vorbis encoding

/* Endian-ness options. */

pub static SF_ENDIAN_FILE : FORMAT_TYPE         = 0x00000000; // Default file endian-ness
pub static SF_ENDIAN_LITTLE : FORMAT_TYPE       = 0x10000000; // Force little endian-ness
pub static SF_ENDIAN_BIG : FORMAT_TYPE          = 0x20000000; // Force big endian-ness
pub static SF_ENDIAN_CPU : FORMAT_TYPE          = 0x30000000; // Force CPU endian-ness

pub static SF_FORMAT_SUBMASK : FORMAT_TYPE      = 0x0000FFFF;
pub static SF_FORMAT_TYPEMASK : FORMAT_TYPE     = 0x0FFF0000;
pub static SF_FORMAT_ENDMASK : FORMAT_TYPE      = 0x30000000;

pub type SNDFILE = c_void;

pub struct FormatInfo {
    format : i32,
    name : *c_char,
    extension : *c_char
}

extern "C" {
    pub fn sf_open(path : *c_char, mode : SF_MODE, info : *SndInfo) -> *SNDFILE;
    pub fn sf_open_fd(fd : i32, mode : SF_MODE, info : *SndInfo, close_desc : SF_BOOL) -> *SNDFILE;
    pub fn sf_format_check(info : *SndInfo) -> SF_BOOL;

    pub fn sf_seek(sndfile : *SNDFILE, frames : i64, whence : i32) -> i64;
    pub fn sf_command(sndfile : *SNDFILE, cmd : i32, data : *c_void, datasize : i32) -> Error;

    pub fn sf_error(sndfile : *SNDFILE) -> Error;
    pub fn sf_strerror(sndfile : *SNDFILE) -> *c_char;
    pub fn sf_error_number(errnum : i32) -> *c_char;

    pub fn sf_perror(sndfile : *SNDFILE) -> Error;
    pub fn sf_error_str(sndfile : *SNDFILE, string : *c_char, len : i64) ;

    pub fn sf_close(sndfile : *SNDFILE) -> Error;
    pub fn sf_write_sync(sndfile : *SNDFILE) -> ();

    pub fn sf_read_short(sndfile : *SNDFILE, ptr : *mut i16, items : i64) -> i64;
    pub fn sf_read_int(sndfile : *SNDFILE, ptr : *mut i32, items : i64) -> i64;
    pub fn sf_read_float(sndfile : *SNDFILE, ptr : *mut f32, items : i64) -> i64;
    pub fn sf_read_double(sndfile : *SNDFILE, ptr : *mut f64, items : i64) -> i64;

    pub fn sf_readf_short(sndfile : *SNDFILE, ptr : *mut i16, frames : i64) -> i64;
    pub fn sf_readf_int(sndfile : *SNDFILE, ptr : *mut i32, frames : i64) -> i64;
    pub fn sf_readf_float(sndfile : *SNDFILE, ptr : *mut f32, frames : i64) -> i64;
    pub fn sf_readf_double(sndfile : *SNDFILE, ptr : *mut f64, frames : i64) -> i64;

    pub fn sf_write_short(sndfile : *SNDFILE, ptr : *mut i16, items : i64) -> i64;
    pub fn sf_write_int(sndfile : *SNDFILE, ptr : *mut i32, items : i64) -> i64;
    pub fn sf_write_float(sndfile : *SNDFILE, ptr : *mut f32, items : i64) -> i64;
    pub fn sf_write_double(sndfile : *SNDFILE, ptr : *mut f64, items : i64) -> i64;

    pub fn sf_writef_short(sndfile : *SNDFILE, ptr : *mut i16, frames : i64) -> i64;
    pub fn sf_writef_int(sndfile : *SNDFILE, ptr : *mut i32, frames : i64) -> i64;
    pub fn sf_writef_float(sndfile : *SNDFILE, ptr : *mut f32, frames : i64) -> i64;
    pub fn sf_writef_double(sndfile : *SNDFILE, ptr : *mut f64, frames : i64) -> i64;

    pub fn sf_read_raw(sndfile : *SNDFILE, ptr : *c_void, bytes : i64) -> i64;
    pub fn sf_write_raw(sndfile : *SNDFILE, ptr : *c_void, bytes : i64) -> i64;

    pub fn sf_get_string(sndfile : *SNDFILE, str_type : i32) -> *c_char;
    pub fn sf_set_string(sndfile : *SNDFILE, str_type : i32, string : *c_char) -> Error;

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

#[allow(dead_code)];

use super::*;
use std::libc::{c_char, c_void};

pub type SF_MODE = i32;
pub static SFM_READ : SF_MODE   = 0x10;
pub static SFM_WRITE : SF_MODE  = 0x20;
pub static SFM_RDWR : SF_MODE   = 0x30;

pub type SF_ERR = i32;
pub static SF_ERR_NO_ERROR : SF_ERR             = 0;
pub static SF_ERR_UNRECOGNISED_FORMAT : SF_ERR  = 1;
pub static SF_ERR_SYSTEM : SF_ERR               = 2;
pub static SF_ERR_MALFORMED_FILE : SF_ERR       = 3;
pub static SF_ERR_UNSUPPORTED_ENCODING : SF_ERR = 4;

pub type SF_STR = i32;
pub static SF_STR_TITLE : SF_STR        = 0x01;
pub static SF_STR_COPYRIGHT : SF_STR    = 0x02;
pub static SF_STR_SOFTWARE : SF_STR     = 0x03;
pub static SF_STR_ARTIST : SF_STR       = 0x04;
pub static SF_STR_COMMENT : SF_STR      = 0x05;
pub static SF_STR_DATE : SF_STR         = 0x06;
pub static SF_STR_ALBUM : SF_STR        = 0x07;
pub static SF_STR_LICENSE : SF_STR      = 0x08;
pub static SF_STR_TRACKNUMBER : SF_STR  = 0x09;
pub static SF_STR_GENRE : SF_STR        = 0x10;

pub type SF_BOOL = i32;
pub static SF_FALSE : SF_BOOL   = 0;
pub static SF_TRUE : SF_BOOL    = 1;

pub type SEEK_MODE = i32;
pub static SEEK_SET : SEEK_MODE = 0;
pub static SEEK_CUR : SEEK_MODE = 1;
pub static SEEK_END : SEEK_MODE = 2;

pub type FORMAT_TYPE = i32;
pub static SF_FORMAT_WAV : FORMAT_TYPE          = 0x010000;   // Microsoft WAV format (little endian)
pub static SF_FORMAT_AIFF : FORMAT_TYPE         = 0x020000;   // Apple/SGI AIFF format (big endian)
pub static SF_FORMAT_AU : FORMAT_TYPE           = 0x030000;   // Sun/NeXT AU format (big endian)
pub static SF_FORMAT_RAW : FORMAT_TYPE          = 0x040000;   // RAW PCM data
pub static SF_FORMAT_PAF : FORMAT_TYPE          = 0x050000;   // Ensoniq PARIS file format
pub static SF_FORMAT_SVX : FORMAT_TYPE          = 0x060000;   // Amiga IFF / SVX8 / SV16 format
pub static SF_FORMAT_NIST : FORMAT_TYPE         = 0x070000;   // Sphere NIST format
pub static SF_FORMAT_VOC : FORMAT_TYPE          = 0x080000;   // VOC files
pub static SF_FORMAT_IRCAM : FORMAT_TYPE        = 0x0A0000;   // Berkeley/IRCAM/CARL
pub static SF_FORMAT_W64 : FORMAT_TYPE          = 0x0B0000;   // Sonic Foundry's 64 bit RIFF/WAV
pub static SF_FORMAT_MAT4 : FORMAT_TYPE         = 0x0C0000;   // Matlab (tm) V4.2 / GNU Octave 2.0
pub static SF_FORMAT_MAT5 : FORMAT_TYPE         = 0x0D0000;   // Matlab (tm) V5.0 / GNU Octave 2.1
pub static SF_FORMAT_PVF : FORMAT_TYPE          = 0x0E0000;   // Portable Voice Format
pub static SF_FORMAT_XI : FORMAT_TYPE           = 0x0F0000;   // Fasttracker 2 Extended Instrument
pub static SF_FORMAT_HTK : FORMAT_TYPE          = 0x100000;   // HMM Tool Kit format
pub static SF_FORMAT_SDS : FORMAT_TYPE          = 0x110000;   // Midi Sample Dump Standard
pub static SF_FORMAT_AVR : FORMAT_TYPE          = 0x120000;   // Audio Visual Research
pub static SF_FORMAT_WAVEX : FORMAT_TYPE        = 0x130000;   // MS WAVE with WAVEFORMATEX
pub static SF_FORMAT_SD2 : FORMAT_TYPE          = 0x160000;   // Sound Designer 2
pub static SF_FORMAT_FLAC : FORMAT_TYPE         = 0x170000;   // FLAC lossless file format
pub static SF_FORMAT_CAF : FORMAT_TYPE          = 0x180000;   // Core Audio File format
pub static SF_FORMAT_WVE : FORMAT_TYPE          = 0x190000;   // Psion WVE format
pub static SF_FORMAT_OGG : FORMAT_TYPE          = 0x200000;   // Xiph OGG container
pub static SF_FORMAT_MPC2K : FORMAT_TYPE        = 0x210000;   // Akai MPC 2000 sampler
pub static SF_FORMAT_RF64 : FORMAT_TYPE         = 0x220000;   // RF64 WAV file
/* Subtypes from here on. */
pub static SF_FORMAT_PCM_S8 : FORMAT_TYPE       = 0x0001;     // Signed 8 bit data
pub static SF_FORMAT_PCM_16 : FORMAT_TYPE       = 0x0002;     // Signed 16 bit data
pub static SF_FORMAT_PCM_24 : FORMAT_TYPE       = 0x0003;     // Signed 24 bit data
pub static SF_FORMAT_PCM_32 : FORMAT_TYPE       = 0x0004;     // Signed 32 bit data
pub static SF_FORMAT_PCM_U8 : FORMAT_TYPE       = 0x0005;     // Unsigned 8 bit data (WAV and RAW only)
pub static SF_FORMAT_FLOAT : FORMAT_TYPE        = 0x0006;     // 32 bit float data
pub static SF_FORMAT_DOUBLE : FORMAT_TYPE       = 0x0007;     // 64 bit float data
pub static SF_FORMAT_ULAW : FORMAT_TYPE         = 0x0010;     // U-Law encoded
pub static SF_FORMAT_ALAW : FORMAT_TYPE         = 0x0011;     // A-Law encoded
pub static SF_FORMAT_IMA_ADPCM : FORMAT_TYPE    = 0x0012;     // IMA ADPCM
pub static SF_FORMAT_MS_ADPCM : FORMAT_TYPE     = 0x0013;     // Microsoft ADPCM
pub static SF_FORMAT_GSM610 : FORMAT_TYPE       = 0x0020;     // GSM 6.10 encoding
pub static SF_FORMAT_VOX_ADPCM : FORMAT_TYPE    = 0x0021;     // Oki Dialogic ADPCM encoding
pub static SF_FORMAT_G721_32 : FORMAT_TYPE      = 0x0030;     // 32kbs G721 ADPCM encoding
pub static SF_FORMAT_G723_24 : FORMAT_TYPE      = 0x0031;     // 24kbs G723 ADPCM encoding
pub static SF_FORMAT_G723_40 : FORMAT_TYPE      = 0x0032;     // 40kbs G723 ADPCM encoding
pub static SF_FORMAT_DWVW_12 : FORMAT_TYPE      = 0x0040;     // 12 bit Delta Width Variable Word encoding
pub static SF_FORMAT_DWVW_16 : FORMAT_TYPE      = 0x0041;     // 16 bit Delta Width Variable Word encoding
pub static SF_FORMAT_DWVW_24 : FORMAT_TYPE      = 0x0042;     // 24 bit Delta Width Variable Word encoding
pub static SF_FORMAT_DWVW_N : FORMAT_TYPE       = 0x0043;     // N bit Delta Width Variable Word encoding
pub static SF_FORMAT_DPCM_8 : FORMAT_TYPE       = 0x0050;     // 8 bit differential PCM (XI only)
pub static SF_FORMAT_DPCM_16 : FORMAT_TYPE      = 0x0051;     // 16 bit differential PCM (XI only)
pub static SF_FORMAT_VORBIS : FORMAT_TYPE       = 0x0060;     // Xiph Vorbis encoding

/* Endian-ness options. */

pub static SF_ENDIAN_FILE : FORMAT_TYPE         = 0x00000000; // Default file endian-ness
pub static SF_ENDIAN_LITTLE : FORMAT_TYPE       = 0x10000000; // Force little endian-ness
pub static SF_ENDIAN_BIG : FORMAT_TYPE          = 0x20000000; // Force big endian-ness
pub static SF_ENDIAN_CPU : FORMAT_TYPE          = 0x30000000; // Force CPU endian-ness

pub static SF_FORMAT_SUBMASK : FORMAT_TYPE      = 0x0000FFFF;
pub static SF_FORMAT_TYPEMASK : FORMAT_TYPE     = 0x0FFF0000;
pub static SF_FORMAT_ENDMASK : FORMAT_TYPE      = 0x30000000;

pub type SNDFILE = c_void;

pub struct FormatInfo {
    format : i32,
    name : *c_char,
    extension : *c_char
}

extern "C" {
    pub fn sf_open(path : *c_char, mode : SF_MODE, info : *SndInfo) -> *SNDFILE;
    pub fn sf_open_fd(fd : i32, mode : SF_MODE, info : *SndInfo, close_desc : SF_BOOL) -> *SNDFILE;
    pub fn sf_format_check(info : *SndInfo) -> SF_BOOL;

    pub fn sf_seek(sndfile : *SNDFILE, frames : i64, whence : i32) -> i64;
    pub fn sf_command(sndfile : *SNDFILE, cmd : i32, data : *c_void, datasize : i32) -> Error;

    pub fn sf_error(sndfile : *SNDFILE) -> Error;
    pub fn sf_strerror(sndfile : *SNDFILE) -> *c_char;
    pub fn sf_error_number(errnum : i32) -> *c_char;

    pub fn sf_perror(sndfile : *SNDFILE) -> Error;
    pub fn sf_error_str(sndfile : *SNDFILE, string : *c_char, len : i64) ;

    pub fn sf_close(sndfile : *SNDFILE) -> Error;
    pub fn sf_write_sync(sndfile : *SNDFILE) -> ();

    pub fn sf_read_short(sndfile : *SNDFILE, ptr : *mut i16, items : i64) -> i64;
    pub fn sf_read_int(sndfile : *SNDFILE, ptr : *mut i32, items : i64) -> i64;
    pub fn sf_read_float(sndfile : *SNDFILE, ptr : *mut f32, items : i64) -> i64;
    pub fn sf_read_double(sndfile : *SNDFILE, ptr : *mut f64, items : i64) -> i64;

    pub fn sf_readf_short(sndfile : *SNDFILE, ptr : *mut i16, frames : i64) -> i64;
    pub fn sf_readf_int(sndfile : *SNDFILE, ptr : *mut i32, frames : i64) -> i64;
    pub fn sf_readf_float(sndfile : *SNDFILE, ptr : *mut f32, frames : i64) -> i64;
    pub fn sf_readf_double(sndfile : *SNDFILE, ptr : *mut f64, frames : i64) -> i64;

    pub fn sf_write_short(sndfile : *SNDFILE, ptr : *mut i16, items : i64) -> i64;
    pub fn sf_write_int(sndfile : *SNDFILE, ptr : *mut i32, items : i64) -> i64;
    pub fn sf_write_float(sndfile : *SNDFILE, ptr : *mut f32, items : i64) -> i64;
    pub fn sf_write_double(sndfile : *SNDFILE, ptr : *mut f64, items : i64) -> i64;

    pub fn sf_writef_short(sndfile : *SNDFILE, ptr : *mut i16, frames : i64) -> i64;
    pub fn sf_writef_int(sndfile : *SNDFILE, ptr : *mut i32, frames : i64) -> i64;
    pub fn sf_writef_float(sndfile : *SNDFILE, ptr : *mut f32, frames : i64) -> i64;
    pub fn sf_writef_double(sndfile : *SNDFILE, ptr : *mut f64, frames : i64) -> i64;

    pub fn sf_read_raw(sndfile : *SNDFILE, ptr : *c_void, bytes : i64) -> i64;
    pub fn sf_write_raw(sndfile : *SNDFILE, ptr : *c_void, bytes : i64) -> i64;

    pub fn sf_get_string(sndfile : *SNDFILE, str_type : i32) -> *c_char;
    pub fn sf_set_string(sndfile : *SNDFILE, str_type : i32, string : *c_char) -> Error;

}<|endoftext|>


<commit_before>pub use std::path::Path;
pub use std::fs::File;
pub use std::error::Error;

pub use runtime::Runtime;

mod file;
mod parser;

pub trait StorageBackend {

    fn name(&self) -> String;

    fn create(&self, file : File)   -> Option<Error>;
    fn read(&self, path: Path)      -> Result<File, Error>;
    fn update(&self, file : File)   -> Option<Error>;
    fn destroy(&self, path: Path)   -> Option<Error>;

}
<commit_msg>Remove old code<commit_after>pub use std::path::Path;
pub use std::fs::File;
pub use std::error::Error;

pub use runtime::Runtime;

mod file;
mod parser;

<|endoftext|>


<commit_before>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
use sdl2::event::Event;
use sdl2::event::Event::{TextInput, TextEditing, KeyDown};
use sdl2::keyboard::{start_text_input, stop_text_input, is_text_input_active};
use sdl2::keycode::*;

use ui::{compute_text_box_bounds, draw_text_box};

use super::super::ui::{UiFont, UiBox};
use super::{ActiveView, PassiveView, DisplayViewContext};

pub struct TextInputDialogView<'a, TFont:'a, TBox:'a> {
    input_state: String,
    previous_state: String,
    prompt: String,
    cursor: String,
    bg_color: (u8, u8, u8),
    coords: (int, int),
    box_size: (uint, uint),
    text_gap: uint,
    ui_font: &'a TFont,
    ui_box: &'a TBox,
    started: bool,
    box_content: Vec<String>
}

pub struct DisplayClearerPassiveView {
    bg_color: (u8, u8, u8)
}

impl<'a, TFont: UiFont, TBox: UiBox> TextInputDialogView<'a, TFont, TBox> {
    pub fn new(
        ui_font: &'a TFont,
        ui_box: &'a TBox,
        seed_state: Option<String>,
        preface: &'a [String],
        prompt: String,
        cursor: String,
        bg_color: (u8,u8,u8),
        coords: (int, int),
        text_gap: uint)
            -> TextInputDialogView<'a, TFont, TBox> {
        let mut bc = Vec::new();
        bc.push_all(preface);
        bc.push("".to_string());

        let mut ret = TextInputDialogView {
            input_state: match seed_state { Some(i) => i, None => "".to_string() },
            previous_state: "".to_string(),
            prompt: prompt,
            cursor: cursor,
            bg_color: bg_color,
            coords: coords,
            box_size: (15,4),
            text_gap: text_gap,
            ui_font: ui_font,
            ui_box: ui_box,
            started: false,
            box_content: bc
        };
        ret.update_content();
        ret
    }

    fn update_content(&mut self) {
        self.box_content.pop();
        self.box_content.push("".to_string());
        let bc_last = self.box_content.len() - 1;
        self.box_content[bc_last].push_str(self.prompt.as_slice());
        self.box_content[bc_last].push_str(" ");
        let is_last = self.input_state.len();
        self.box_content[bc_last].push_str(self.input_state.slice(0, is_last));
        self.box_content[bc_last].push_str(self.cursor.as_slice());
    }
}

impl<'a, TViewCtx: DisplayViewContext, TFont: UiFont, TBox: UiBox>
        ActiveView<TViewCtx, String> for TextInputDialogView<'a, TFont, TBox> {
    fn active_update<'a>(
        &'a mut self,
        ctx: &TViewCtx,
        events: &[Event],
        _ms_time: u64,
        _passives: & mut Vec<&mut PassiveView<TViewCtx> >) -> Option<String> {
        //
        if !self.started {
            self.started = true;
            // call into SDL2 start text editing stuff
            println!("call to start_text_input()");
            start_text_input();
        }
        self.previous_state = self.input_state.clone();
        let mut out = None;
        for event in events.iter() {
            match *event {
                KeyDown(_, _, key, _, _) =>
                    match key {
                        Return => {
                            out = Some(self.input_state.clone());
                            stop_text_input();
                            break;
                        },
                        Backspace => {
                            self.input_state.pop();
                        }
                        Escape => {
                            out = Some("".to_string());
                            stop_text_input();
                            break;
                        },
                        _ => {}
                    },
                TextInput(_, _, ref txt) => {
                    out = None;
                    self.input_state.push_str(txt.as_slice());
                },
                _ => {}
            }
        }
        if self.previous_state != self.input_state {
            self.update_content();
        }
        draw_text_box(ctx.get_display(), self.coords, self.box_size, self.bg_color, self.box_content.as_slice(), self.ui_font,
                      self.ui_box, self.text_gap);
        out
    }
}

impl<'a, TViewCtx: DisplayViewContext, TFont: UiFont, TBox: UiBox>
        PassiveView<TViewCtx> for TextInputDialogView<'a, TFont, TBox> {
    fn passive_update(&mut self, _ctx: &TViewCtx, _t: u64) {
        // should never be passive, because the active_update() impl
        // doesn't yield_to() any other views, so we can put the logic
        // there
    }
}

impl DisplayClearerPassiveView {
    pub fn new(bgc: (u8, u8, u8)) -> DisplayClearerPassiveView {
        DisplayClearerPassiveView { bg_color: bgc }
    }
}

impl<TViewCtx: DisplayViewContext> PassiveView<TViewCtx> for DisplayClearerPassiveView {
    fn passive_update(&mut self, ctx: &TViewCtx, _time: u64) {
        println!("in passive_update for DisplayClearer");
        let display = ctx.get_display();
        display.set_draw_color(self.bg_color);
        match display.renderer.clear() {
            Err(e) => panic!("Display Clearer.update(): failed to clear display: {}", e),
            _ => {}
        }
    }
}

impl<TViewCtx: DisplayViewContext> ActiveView<TViewCtx, ()>
        for DisplayClearerPassiveView {
    fn active_update<'a>(&'a mut self, _ctx: &TViewCtx, _e: &[Event], _t: u64,
              _p: &mut Vec<&mut PassiveView<TViewCtx> >)
        -> Option<()> {
            panic!("this should never be called.");
    }
}
<commit_msg>text input resizes as needed, now<commit_after>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
use sdl2::event::Event;
use sdl2::event::Event::{TextInput, TextEditing, KeyDown};
use sdl2::keyboard::{start_text_input, stop_text_input, is_text_input_active};
use sdl2::keycode::*;

use ui::{compute_text_box_bounds, draw_text_box};

use super::super::ui::{UiFont, UiBox};
use super::{ActiveView, PassiveView, DisplayViewContext};

pub struct TextInputDialogView<'a, TFont:'a, TBox:'a> {
    input_state: String,
    previous_state: String,
    prompt: String,
    cursor: String,
    bg_color: (u8, u8, u8),
    coords: (int, int),
    box_size: (uint, uint),
    text_gap: uint,
    ui_font: &'a TFont,
    ui_box: &'a TBox,
    started: bool,
    box_content: Vec<String>
}

pub struct DisplayClearerPassiveView {
    bg_color: (u8, u8, u8)
}

impl<'a, TFont: UiFont, TBox: UiBox> TextInputDialogView<'a, TFont, TBox> {
    pub fn new(
        ui_font: &'a TFont,
        ui_box: &'a TBox,
        seed_state: Option<String>,
        preface: &'a [String],
        prompt: String,
        cursor: String,
        bg_color: (u8,u8,u8),
        coords: (int, int),
        text_gap: uint)
            -> TextInputDialogView<'a, TFont, TBox> {
        let mut bc = Vec::new();
        bc.push_all(preface);
        bc.push("".to_string());

        let mut ret = TextInputDialogView {
            input_state: match seed_state { Some(i) => i, None => "".to_string() },
            previous_state: "".to_string(),
            prompt: prompt,
            cursor: cursor,
            bg_color: bg_color,
            coords: coords,
            box_size: (15,4),
            text_gap: text_gap,
            ui_font: ui_font,
            ui_box: ui_box,
            started: false,
            box_content: bc
        };
        ret.update_content();
        ret
    }

    fn update_content(&mut self) {
        self.box_content.pop();
        self.box_content.push("".to_string());
        let bc_last = self.box_content.len() - 1;
        self.box_content[bc_last].push_str(self.prompt.as_slice());
        self.box_content[bc_last].push_str(" ");
        let is_last = self.input_state.len();
        self.box_content[bc_last].push_str(self.input_state.slice(0, is_last));
        self.box_content[bc_last].push_str(self.cursor.as_slice());
        self.box_size = compute_text_box_bounds(self.box_content.as_slice(), self.ui_font, self.ui_box, self.text_gap);
    }
}

impl<'a, TViewCtx: DisplayViewContext, TFont: UiFont, TBox: UiBox>
        ActiveView<TViewCtx, String> for TextInputDialogView<'a, TFont, TBox> {
    fn active_update<'a>(
        &'a mut self,
        ctx: &TViewCtx,
        events: &[Event],
        _ms_time: u64,
        _passives: & mut Vec<&mut PassiveView<TViewCtx> >) -> Option<String> {
        //
        if !self.started {
            self.started = true;
            // call into SDL2 start text editing stuff
            println!("call to start_text_input()");
            start_text_input();
        }
        self.previous_state = self.input_state.clone();
        let mut out = None;
        for event in events.iter() {
            match *event {
                KeyDown(_, _, key, _, _) =>
                    match key {
                        Return => {
                            out = Some(self.input_state.clone());
                            stop_text_input();
                            break;
                        },
                        Backspace => {
                            self.input_state.pop();
                        }
                        Escape => {
                            out = Some("".to_string());
                            stop_text_input();
                            break;
                        },
                        _ => {}
                    },
                TextInput(_, _, ref txt) => {
                    out = None;
                    self.input_state.push_str(txt.as_slice());
                },
                _ => {}
            }
        }
        if self.previous_state != self.input_state {
            self.update_content();
        }
        draw_text_box(ctx.get_display(), self.coords, self.box_size, self.bg_color, self.box_content.as_slice(), self.ui_font,
                      self.ui_box, self.text_gap);
        out
    }
}

impl<'a, TViewCtx: DisplayViewContext, TFont: UiFont, TBox: UiBox>
        PassiveView<TViewCtx> for TextInputDialogView<'a, TFont, TBox> {
    fn passive_update(&mut self, _ctx: &TViewCtx, _t: u64) {
        // should never be passive, because the active_update() impl
        // doesn't yield_to() any other views, so we can put the logic
        // there
    }
}

impl DisplayClearerPassiveView {
    pub fn new(bgc: (u8, u8, u8)) -> DisplayClearerPassiveView {
        DisplayClearerPassiveView { bg_color: bgc }
    }
}

impl<TViewCtx: DisplayViewContext> PassiveView<TViewCtx> for DisplayClearerPassiveView {
    fn passive_update(&mut self, ctx: &TViewCtx, _time: u64) {
        println!("in passive_update for DisplayClearer");
        let display = ctx.get_display();
        display.set_draw_color(self.bg_color);
        match display.renderer.clear() {
            Err(e) => panic!("Display Clearer.update(): failed to clear display: {}", e),
            _ => {}
        }
    }
}

impl<TViewCtx: DisplayViewContext> ActiveView<TViewCtx, ()>
        for DisplayClearerPassiveView {
    fn active_update<'a>(&'a mut self, _ctx: &TViewCtx, _e: &[Event], _t: u64,
              _p: &mut Vec<&mut PassiveView<TViewCtx> >)
        -> Option<()> {
            panic!("this should never be called.");
    }
}
<|endoftext|>


<commit_before>use cached_tree_hash::TreeHashCache;
use ethereum_types::H256 as Hash256;

fn run(vec: &Vec<Hash256>, modified_vec: &Vec<Hash256>) {
    let mut cache = TreeHashCache::new(vec, 0).unwrap();

    cache.update(modified_vec).unwrap();
}

fn main() {
    let n = 2048;

    let vec: Vec<Hash256> = (0..n).map(|_| Hash256::random()).collect();

    let mut modified_vec = vec.clone();
    modified_vec[n - 1] = Hash256::random();

    for _ in 0..100 {
        run(&vec, &modified_vec);
    }
}
<commit_msg>Modify example execution counts<commit_after>use cached_tree_hash::TreeHashCache;
use ethereum_types::H256 as Hash256;

fn run(vec: &Vec<Hash256>, modified_vec: &Vec<Hash256>) {
    let mut cache = TreeHashCache::new(vec, 0).unwrap();

    cache.update(modified_vec).unwrap();
}

fn main() {
    let n = 2048;

    let vec: Vec<Hash256> = (0..n).map(|_| Hash256::random()).collect();

    let mut modified_vec = vec.clone();
    modified_vec[n - 1] = Hash256::random();

    for _ in 0..10_000 {
        run(&vec, &modified_vec);
    }
}
<|endoftext|>


<commit_before>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

use std::ops::{Add, AddAssign, BitAnd, BitOr, Mul, Sub, Shl, ShlAssign, Shr};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

/// An abstraction trait for keeping different sized integers.
pub trait Sample: PartialEq + Eq + Sized + Clone + Copy +
                  Add<Output = Self> + AddAssign +
                  BitAnd<Self, Output = Self> + BitOr<Self, Output = Self> +
                  Mul<Output = Self> + Shl<u32, Output = Self>  +
                  ShlAssign<u32> + Shr<u32, Output = Self> +
                  Shr<i8, Output = Self> + Shr<i32, Output = Self> +
                  Sub<Output = Self> {
  /// The normal size for the current a `Sample`.
  type Normal;

  /// The size, in bits, for the `Sample::Normal`.
  fn size() -> usize;

  /// The size, in bits, for the `Sample`.
  fn size_extended() -> usize;

  /// Convert the extended `Sample` to the normal.
  fn to_normal(sample: Self) -> Option<Self::Normal>;

  /// Convert an i8 into a `Sample`.
  fn from_i8(sample: i8) -> Self;

  /// Convert an i16 into a `Sample`.
  fn from_i16(sample: i16) -> Self;

  /// Convert an i32 into a `Sample`.
  ///
  /// With `Sample` sometimes being smaller than a i32, there is a chance
  /// for this function to return an incorrect number. So when the number is
  /// larger of smaller than the current `Sample`, it returns `None`
  /// otherwise `Some(sample)`.
  fn from_i32(sample: i32) -> Option<Self>;

  /// Convert an i32 into a `Sample`.
  fn from_i32_lossy(sample: i32) -> Self;
}

/// A trait for defining the size of a sample.
pub trait SampleSize {
  /// The internal integer size used with `Stream::iter`.
  ///
  /// Rather than making the user of `Stream::iter` will remember what the
  /// extended size of the output sample will be, this is to map to the
  /// value based on the current integer size used.
  type Extended: Sample;
}

impl SampleSize for i8 {
  type Extended = i16;
}

impl SampleSize for i16 {
  type Extended = i32;
}

impl SampleSize for i32 {
  type Extended = i64;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parser! {
      to_custom_error!(slice, tag!("fLaC"), HeaderParser)
    };

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<commit_msg>Add trait for a Write extension for bytes<commit_after>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

use std::ops::{Add, AddAssign, BitAnd, BitOr, Mul, Sub, Shl, ShlAssign, Shr};
use std::io;

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

/// An abstraction trait for keeping different sized integers.
pub trait Sample: PartialEq + Eq + Sized + Clone + Copy +
                  Add<Output = Self> + AddAssign +
                  BitAnd<Self, Output = Self> + BitOr<Self, Output = Self> +
                  Mul<Output = Self> + Shl<u32, Output = Self>  +
                  ShlAssign<u32> + Shr<u32, Output = Self> +
                  Shr<i8, Output = Self> + Shr<i32, Output = Self> +
                  Sub<Output = Self> {
  /// The normal size for the current a `Sample`.
  type Normal;

  /// The size, in bits, for the `Sample::Normal`.
  fn size() -> usize;

  /// The size, in bits, for the `Sample`.
  fn size_extended() -> usize;

  /// Convert the extended `Sample` to the normal.
  fn to_normal(sample: Self) -> Option<Self::Normal>;

  /// Convert an i8 into a `Sample`.
  fn from_i8(sample: i8) -> Self;

  /// Convert an i16 into a `Sample`.
  fn from_i16(sample: i16) -> Self;

  /// Convert an i32 into a `Sample`.
  ///
  /// With `Sample` sometimes being smaller than a i32, there is a chance
  /// for this function to return an incorrect number. So when the number is
  /// larger of smaller than the current `Sample`, it returns `None`
  /// otherwise `Some(sample)`.
  fn from_i32(sample: i32) -> Option<Self>;

  /// Convert an i32 into a `Sample`.
  fn from_i32_lossy(sample: i32) -> Self;
}

/// A trait for defining the size of a sample.
pub trait SampleSize {
  /// The internal integer size used with `Stream::iter`.
  ///
  /// Rather than making the user of `Stream::iter` will remember what the
  /// extended size of the output sample will be, this is to map to the
  /// value based on the current integer size used.
  type Extended: Sample;
}

impl SampleSize for i8 {
  type Extended = i16;
}

impl SampleSize for i16 {
  type Extended = i32;
}

impl SampleSize for i32 {
  type Extended = i64;
}

pub trait WriteExtension: io::Write {
  fn write_u8(&mut self, number: u8) -> io::Result<()>;

  fn write_be_u16(&mut self, number: u16) -> io::Result<()>;
  fn write_le_u16(&mut self, number: u16) -> io::Result<()>;

  fn write_be_u24(&mut self, number: u32) -> io::Result<()>;
  fn write_le_u24(&mut self, number: u32) -> io::Result<()>;

  fn write_be_u32(&mut self, number: u32) -> io::Result<()>;
  fn write_le_u32(&mut self, number: u32) -> io::Result<()>;

  fn write_be_u64(&mut self, number: u64) -> io::Result<()>;
  fn write_le_u64(&mut self, number: u64) -> io::Result<()>;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parser! {
      to_custom_error!(slice, tag!("fLaC"), HeaderParser)
    };

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

fn get_input() -> std::io::Result<String> {
    let mut file = File::open("02.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;

    Ok(contents)
}

fn get_char_histogram(input: &str) -> HashMap<char, usize> {
    let mut result = HashMap::new();

    for c in input.chars() {
        let v = match result.get(&c) {
            Some(&v) => v,
            None => 0
        };

        result.insert(c, v + 1);
    }

    result
}

fn get_checksum(ids: &Vec<String>) -> usize {
    let histograms: Vec<HashMap<char, usize>> = ids.iter()
        .map(|x| get_char_histogram(x))
        .collect();

    let exactly_two = histograms.iter()
        .filter(|hist| hist.iter().any(|(_, &v)| v == 2))
        .count();

    let exactly_three = histograms.iter()
        .filter(|hist| hist.iter().any(|(_, &v)| v == 3))
        .count();

    return exactly_two * exactly_three
}

fn diff_id(id1: &str, id2: &str) -> usize {
    id1.chars()
    .zip(id2.chars())
    .filter(|(c1, c2)| c1 != c2)
    .count()
}

fn find_correct_ids<'a>(ids: &'a Vec<String>) -> Option<(&'a str, &'a str)> {
    for (i, id1) in ids.iter().enumerate() {
        for id2 in ids.iter().skip(i + 1) {
            let diff = diff_id(id1, id2);

            if diff == 1 {
                return Some((id1, id2));
            }
        }
    }

    None
}

fn main() {
    let ids: Vec<String> = get_input().unwrap()
        .lines()
        .map(|x| x.to_string())
        .filter(|x| x != "")
        .collect();

    println!("Part 1: {}", get_checksum(&ids));

    if let Some((id1, id2)) = find_correct_ids(&ids) {
        let chars = id1.chars()
            .zip(id2.chars())
            .filter(|(c1, c2)| c1 == c2)
            .fold(String::new(), |acc, (c, _)| acc + &c.to_string());

        println!("Part 2: {}", chars);
    }
}
<commit_msg>Remove unnecessary lifetime<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

fn get_input() -> std::io::Result<String> {
    let mut file = File::open("02.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;

    Ok(contents)
}

fn get_char_histogram(input: &str) -> HashMap<char, usize> {
    let mut result = HashMap::new();

    for c in input.chars() {
        let v = match result.get(&c) {
            Some(&v) => v,
            None => 0
        };

        result.insert(c, v + 1);
    }

    result
}

fn get_checksum(ids: &Vec<String>) -> usize {
    let histograms: Vec<HashMap<char, usize>> = ids.iter()
        .map(|x| get_char_histogram(x))
        .collect();

    let exactly_two = histograms.iter()
        .filter(|hist| hist.iter().any(|(_, &v)| v == 2))
        .count();

    let exactly_three = histograms.iter()
        .filter(|hist| hist.iter().any(|(_, &v)| v == 3))
        .count();

    return exactly_two * exactly_three
}

fn diff_id(id1: &str, id2: &str) -> usize {
    id1.chars()
    .zip(id2.chars())
    .filter(|(c1, c2)| c1 != c2)
    .count()
}

fn find_correct_ids(ids: &Vec<String>) -> Option<(&str, &str)> {
    for (i, id1) in ids.iter().enumerate() {
        for id2 in ids.iter().skip(i + 1) {
            let diff = diff_id(id1, id2);

            if diff == 1 {
                return Some((id1, id2));
            }
        }
    }

    None
}

fn main() {
    let ids: Vec<String> = get_input().unwrap()
        .lines()
        .map(|x| x.to_string())
        .filter(|x| x != "")
        .collect();

    println!("Part 1: {}", get_checksum(&ids));

    if let Some((id1, id2)) = find_correct_ids(&ids) {
        let chars = id1.chars()
            .zip(id2.chars())
            .filter(|(c1, c2)| c1 == c2)
            .fold(String::new(), |acc, (c, _)| acc + &c.to_string());

        println!("Part 2: {}", chars);
    }
}
<|endoftext|>