<commit_before>use std::path::Path;
use std::collections::BTreeMap;
use linear_map::LinearMap;
use version_vector::*;
use storage::{Storage, StorageIterator};
use database::Database;
use bincode::{self, serde as bincode_serde};
use fabric::*;
use utils::GenericError;
use rand::{Rng, thread_rng};
use hash::hash;

const PEER_LOG_SIZE: usize = 1000;

#[repr(u8)]
enum VNodeStatus {
    InSync,
    Syncing,
    Zombie,
}

pub struct VNode {
    pub state: VNodeState,
    migrations: LinearMap<(NodeId, u64), Migration>,
    syncs: LinearMap<(NodeId, u64), Synchronization>,
}

pub struct VNodeState {
    num: u16,
    peers: LinearMap<u64, VNodePeer>,
    clock: BitmappedVersionVector,
    log: BTreeMap<u64, Vec<u8>>,
    storage: Storage,
    unflushed_coord_writes: usize,
}

struct VNodePeer {
    knowledge: u64,
    log: BTreeMap<u64, Vec<u8>>,
}

enum Migration {
    Outgoing {
        vnode: u16,
        cookie: u64,
        peer: NodeId,
        iterator: StorageIterator,
        count: u64,
    },
    Incomming {
        vnode: u16,
        cookie: u64,
        peer: NodeId,
        count: u64,
    },
}

enum Synchronization {
    Outgoing {
        clock_in_peer: BitmappedVersion,
        clock_snapshot: BitmappedVersion,
        missing_dots: BitmappedVersionDelta,
        vnode: u16,
        cookie: u64,
        peer: NodeId,
        count: u64,
    },
    Incomming {
        vnode: u16,
        cookie: u64,
        peer: NodeId,
        count: u64,
    },
}

impl VNodePeer {
    fn new() -> VNodePeer {
        VNodePeer {
            knowledge: 0,
            log: Default::default(),
        }
    }

    fn advance_knowledge(&mut self, until: u64) {
        debug_assert!(until > self.knowledge);
        self.knowledge = until;
    }

    fn log(&mut self, dot: u64, key: Vec<u8>) {
        let prev = self.log.insert(dot, key);
        debug_assert!(prev.is_none());
        while self.log.len() > PEER_LOG_SIZE {
            let min = self.log.keys().next().cloned().unwrap();
            self.log.remove(&min).unwrap();
        }
    }

    fn get(&self, dot: u64) -> Option<Vec<u8>> {
        self.log.get(&dot).cloned()
    }
}

macro_rules! forward {
    ($db: expr, $from: expr, $msg: expr, $emsg: ident, $r: expr) => (
        match $r {
            Ok(ok) => ok,
            Err(e) => {
                $db.fabric.send_message($from,  $emsg {
                    cookie: $msg.cookie,
                    vnode: $msg.vnode,
                    result: Err(e),
                }).unwrap();
                return;
            }
        }
    );
    ($this: expr, $db: expr, $from: expr, $msg: expr, $emsg: ident, $col: ident, $f: ident) => {
        let cookie = $msg.cookie;
        if {
            let sync = forward!($db, $from, $msg, $emsg,
                $this.$col
                    .get_mut(&($from, cookie))
                    .ok_or(FabricMsgError::CookieNotFound));
            sync.$f($db, &mut $this.state, $msg)
        } {
            $this.$col.remove(&($from, cookie)).unwrap();
        }
    }
}

impl VNode {
    pub fn new(storage_dir: &Path, num: u16) -> VNode {
        VNode {
            state: VNodeState {
                num: num,
                clock: BitmappedVersionVector::new(),
                peers: Default::default(),
                log: Default::default(),
                storage: Storage::open(storage_dir, num as i32, true).unwrap(),
                unflushed_coord_writes: 0,
            },
            migrations: Default::default(),
            syncs: Default::default(),
        }
    }

    fn cookie(&mut self) -> u64 {
        thread_rng().gen()
    }

    // HANDLERS
    pub fn handler_bootstrap_start(&mut self, db: &Database, from: NodeId,
                                   msg: FabricBootstrapStart) {
        let cookie = msg.cookie;
        let mut migration = Migration::Outgoing {
            vnode: self.state.num,
            cookie: cookie,
            iterator: self.state.storage.iter(),
            peer: from,
            count: 0,
        };
        migration.on_start(db, &mut self.state, msg);

        let p = self.migrations.insert((from, cookie), migration);
        assert!(p.is_none());
    }

    pub fn handler_bootstrap_send(&mut self, db: &Database, from: NodeId, msg: FabricBootstrapSend) {
        forward!(self, db, from, msg, FabricBootstrapFin, migrations, on_send);
    }

    pub fn handler_bootstrap_ack(&mut self, db: &Database, from: NodeId, msg: FabricBootstrapAck) {
        forward!(self, db, from, msg, FabricBootstrapFin, migrations, on_ack);
    }

    pub fn handler_bootstrap_fin(&mut self, db: &Database, from: NodeId, msg: FabricBootstrapFin) {
        forward!(self, db, from, msg, FabricBootstrapFin, migrations, on_fin);
    }

    pub fn handler_sync_send(&mut self, db: &Database, from: NodeId, msg: MsgSyncSend) {
        forward!(self, db, from, msg, MsgSyncFin, syncs, on_send);
    }

    pub fn handler_sync_ack(&mut self, db: &Database, from: NodeId, msg: MsgSyncAck) {
        forward!(self, db, from, msg, MsgSyncFin, syncs, on_ack);
    }

    pub fn handler_sync_fin(&mut self, db: &Database, from: NodeId, msg: MsgSyncFin) {
        forward!(self, db, from, msg, MsgSyncFin, syncs, on_fin);
    }

    /// //////
    pub fn start_migration(&mut self, db: &Database) {
        let cookie = self.cookie();
        let mut nodes = db.dht.nodes_for_vnode(self.state.num, db.replication_factor, false);
        thread_rng().shuffle(&mut nodes);
        for node in nodes {
            if node == db.dht.node() {
                continue;
            }
            let migration = Migration::Incomming {
                vnode: self.state.num,
                cookie: cookie,
                peer: node,
                count: 0,
            };

            db.fabric
                .send_message(node,
                              FabricBootstrapStart {
                                  cookie: cookie,
                                  vnode: self.state.num,
                              })
                .unwrap();

            let p = self.migrations.insert((node, cookie), migration);
            assert!(p.is_none());
            return;
        }
        unreachable!();
    }

    // pub fn start_sync(&mut self, db: &Database) {
    //     self.state.peers.iter().max_by_key(|&(&n, vp)|
    //         self.state.clock.get(n).map_or(0, |bv| bv.base()) - vp.knowledge
    //     )
    //     .map(|(&n, vp)| {
    //         let cookie = self.cookie();
    //         let sync = Synchronization::Incomming {
    //             peer: n,
    //             cookie: cookie,
    //             vnode: self.state.num,
    //             count: 0,
    //         };
    //
    //         db.fabric
    //             .send_message(n,
    //                           MsgSyncStart {
    //                               cookie: cookie,
    //                               vnode: self.state.num,
    //                           })
    //             .unwrap();
    //         let p = self.syncs.insert((n, cookie), sync);
    //         assert!(p.is_none());
    //         return;
    //     });
    // }
}

impl VNodeState {
    // STORAGE
    pub fn storage_get(&self, key: &[u8]) -> DottedCausalContainer<Vec<u8>> {
        let mut dcc = if let Some(bytes) = self.storage.get_vec(key) {
            bincode_serde::deserialize(&bytes).unwrap()
        } else {
            DottedCausalContainer::new()
        };
        dcc.fill(&self.clock);
        dcc
    }

    pub fn storage_set_local(&mut self, id: u64, key: &[u8], value_opt: Option<&[u8]>,
                             vv: &VersionVector)
                             -> DottedCausalContainer<Vec<u8>> {
        let mut dcc = self.storage_get(key);
        dcc.discard(vv);
        let dot = self.clock.event(id);
        if let Some(value) = value_opt {
            dcc.add(id, dot, value.into());
        }
        dcc.strip(&self.clock);

        if dcc.is_empty() {
            self.storage.del(key);
        } else {
            let mut bytes = Vec::new();
            bincode_serde::serialize_into(&mut bytes, &dcc, bincode::SizeLimit::Infinite).unwrap();
            self.storage.set(key, &bytes);
        }

        self.log.insert(dot, key.into());

        self.unflushed_coord_writes += 1;
        if self.unflushed_coord_writes >= PEER_LOG_SIZE {
            self.unflushed_coord_writes = 0;
            self.storage.sync();
        }

        dcc
    }

    pub fn storage_set_remote(&mut self, key: &[u8], mut new_dcc: DottedCausalContainer<Vec<u8>>,
                              log: Option<u64>) {
        let old_dcc = self.storage_get(key);
        new_dcc.add_to_bvv(&mut self.clock);
        new_dcc.sync(old_dcc);
        new_dcc.strip(&self.clock);

        if new_dcc.is_empty() {
            self.storage.del(key);
        } else {
            let mut bytes = Vec::new();
            bincode_serde::serialize_into(&mut bytes, &new_dcc, bincode::SizeLimit::Infinite)
                .unwrap();
            self.storage.set(key, &bytes);
        }

        if let Some(peer_id) = log {
            self.peers
                .entry(peer_id)
                .or_insert_with(|| VNodePeer::new())
                .log(self.clock.get(peer_id).unwrap().base(), key.into());
        }
    }
}

#[allow(unused_variables)]
impl Synchronization {
    fn outgoing_send(&mut self, db: &Database, state: &mut VNodeState) -> bool {
        match *self {
            Synchronization::Outgoing { peer,
                                        cookie,
                                        vnode,
                                        ref mut missing_dots,
                                        ref mut count,
                                        .. } => {
                let vnpeer = state.peers.get(&hash(peer)).unwrap();
                let kv_opt = missing_dots.next()
                    .and_then(|dot| vnpeer.get(dot))
                    .and_then(|k| state.storage.get_vec(&k).map(|v| (k, v)));
                if let Some((k, v)) = kv_opt {
                    db.fabric
                        .send_message(peer,
                                      MsgSyncSend {
                                          cookie: cookie,
                                          vnode: vnode,
                                          key: k.into(),
                                          container: bincode_serde::deserialize(&v).unwrap(),
                                      })
                        .unwrap();
                    *count += 1;
                    false
                } else {
                    debug!("[{}] synchronization of {} is done", db.dht.node(), vnode);
                    db.fabric
                        .send_message(peer,
                                      MsgSyncFin {
                                          cookie: cookie,
                                          vnode: vnode,
                                          result: Ok(()),
                                      })
                        .unwrap();
                    true
                }
            }
            _ => unreachable!(),
        }
    }

    fn on_start(&mut self, db: &Database, state: &mut VNodeState, msg: MsgSyncStart) -> bool {
        match *self {
            Synchronization::Outgoing { .. } => self.outgoing_send(db, state),
            _ => unreachable!(),
        }
    }

    fn on_send(&mut self, db: &Database, state: &mut VNodeState, msg: MsgSyncSend) -> bool {
        match *self {
            Synchronization::Incomming { peer, vnode, ref mut count, .. } => {
                let mut bytes = Vec::new();
                bincode_serde::serialize_into(&mut bytes,
                                              &msg.container,
                                              bincode::SizeLimit::Infinite)
                    .unwrap();
                state.storage.set(&msg.key, &bytes);

                db.fabric
                    .send_message(peer,
                                  MsgSyncAck {
                                      cookie: msg.cookie,
                                      vnode: vnode,
                                  })
                    .unwrap();

                *count += 1;
                false
            }
            _ => unreachable!(),
        }
    }

    fn on_fin(&mut self, db: &Database, state: &mut VNodeState, msg: MsgSyncFin) -> bool {
        match *self {
            Synchronization::Incomming { peer, .. } => {
                // merge remote clock snapshot into our clocks
                state.storage.sync();
                // send it back as a form of ack-ack
                db.fabric.send_message(peer, msg).unwrap();
            }
            Synchronization::Outgoing { ref clock_in_peer, peer, .. } => {
                let vnpeer = state.peers.get_mut(&hash(peer)).unwrap();
                vnpeer.advance_knowledge(clock_in_peer.base());
            }
        }
        true
    }

    fn on_ack(&mut self, db: &Database, state: &mut VNodeState, msg: MsgSyncAck) -> bool {
        match *self {
            Synchronization::Outgoing { .. } => self.outgoing_send(db, state),
            _ => unreachable!(),
        }
    }
}

#[allow(unused_variables)]
impl Migration {
    fn outgoing_send(&mut self, db: &Database) -> bool {
        match *self {
            Migration::Outgoing { peer, cookie, vnode, ref mut iterator, ref mut count } => {
                let done = !iterator.iter(|k, v| {
                    db.fabric
                        .send_message(peer,
                                      FabricBootstrapSend {
                                          cookie: cookie,
                                          vnode: vnode,
                                          key: k.into(),
                                          container: bincode_serde::deserialize(v).unwrap(),
                                      })
                        .unwrap();
                    *count += 1;
                    false
                });
                if done {
                    debug!("[{}] sync of {} is done", db.dht.node(), vnode);
                    db.fabric
                        .send_message(peer,
                                      FabricBootstrapFin {
                                          cookie: cookie,
                                          vnode: vnode,
                                          result: Ok(()),
                                      })
                        .unwrap();
                }
                done
            }
            _ => unreachable!(),
        }
    }

    fn on_start(&mut self, db: &Database, state: &mut VNodeState, msg: FabricBootstrapStart) -> bool {
        match *self {
            Migration::Outgoing { .. } => self.outgoing_send(db),
            _ => unreachable!(),
        }
    }

    fn on_send(&mut self, db: &Database, state: &mut VNodeState, msg: FabricBootstrapSend) -> bool {
        match *self {
            Migration::Incomming { vnode, peer, ref mut count, .. } => {
                state.storage_set_remote(&msg.key, msg.container, None);
                db.fabric
                    .send_message(peer,
                                  FabricBootstrapAck {
                                      cookie: msg.cookie,
                                      vnode: vnode,
                                  })
                    .unwrap();

                *count += 1;
                false
            }
            _ => unreachable!(),
        }
    }

    fn on_fin(&mut self, db: &Database, state: &mut VNodeState, msg: FabricBootstrapFin) -> bool {
        match *self {
            Migration::Incomming { peer, .. } => {
                state.storage.sync();
                // db.dht.promote_pending_node(vnode: u16, node: NodeId)
                // send it back as a form of ack-ack
                db.fabric.send_message(peer, msg).unwrap();
            }
            Migration::Outgoing { .. } => (),
        }
        true
    }

    fn on_ack(&mut self, db: &Database, state: &mut VNodeState, msg: FabricBootstrapAck) -> bool {
        match *self {
            Migration::Outgoing { .. } => self.outgoing_send(db),
            _ => unreachable!(),
        }
    }
}
<commit_msg>only finished on fin<commit_after>use std::path::Path;
use std::collections::BTreeMap;
use linear_map::LinearMap;
use version_vector::*;
use storage::{Storage, StorageIterator};
use database::Database;
use bincode::{self, serde as bincode_serde};
use fabric::*;
use utils::GenericError;
use rand::{Rng, thread_rng};
use hash::hash;

const PEER_LOG_SIZE: usize = 1000;

#[repr(u8)]
enum VNodeStatus {
    InSync,
    Syncing,
    Zombie,
}

pub struct VNode {
    pub state: VNodeState,
    migrations: LinearMap<(NodeId, u64), Migration>,
    syncs: LinearMap<(NodeId, u64), Synchronization>,
}

pub struct VNodeState {
    num: u16,
    peers: LinearMap<u64, VNodePeer>,
    clock: BitmappedVersionVector,
    log: BTreeMap<u64, Vec<u8>>,
    storage: Storage,
    unflushed_coord_writes: usize,
}

struct VNodePeer {
    knowledge: u64,
    log: BTreeMap<u64, Vec<u8>>,
}

enum Migration {
    Outgoing {
        vnode: u16,
        cookie: u64,
        peer: NodeId,
        iterator: StorageIterator,
        count: u64,
    },
    Incomming {
        vnode: u16,
        cookie: u64,
        peer: NodeId,
        count: u64,
    },
}

enum Synchronization {
    Outgoing {
        clock_in_peer: BitmappedVersion,
        clock_snapshot: BitmappedVersion,
        missing_dots: BitmappedVersionDelta,
        vnode: u16,
        cookie: u64,
        peer: NodeId,
        count: u64,
    },
    Incomming {
        vnode: u16,
        cookie: u64,
        peer: NodeId,
        count: u64,
    },
}

impl VNodePeer {
    fn new() -> VNodePeer {
        VNodePeer {
            knowledge: 0,
            log: Default::default(),
        }
    }

    fn advance_knowledge(&mut self, until: u64) {
        debug_assert!(until > self.knowledge);
        self.knowledge = until;
    }

    fn log(&mut self, dot: u64, key: Vec<u8>) {
        let prev = self.log.insert(dot, key);
        debug_assert!(prev.is_none());
        while self.log.len() > PEER_LOG_SIZE {
            let min = self.log.keys().next().cloned().unwrap();
            self.log.remove(&min).unwrap();
        }
    }

    fn get(&self, dot: u64) -> Option<Vec<u8>> {
        self.log.get(&dot).cloned()
    }
}

macro_rules! forward {
    ($db: expr, $from: expr, $msg: expr, $emsg: ident, $r: expr) => (
        match $r {
            Ok(ok) => ok,
            Err(e) => {
                $db.fabric.send_message($from,  $emsg {
                    cookie: $msg.cookie,
                    vnode: $msg.vnode,
                    result: Err(e),
                }).unwrap();
                return;
            }
        }
    );
    ($this: expr, $db: expr, $from: expr, $msg: expr, $emsg: ident, $col: ident, $f: ident) => {
        let cookie = $msg.cookie;
        if {
            let sync = forward!($db, $from, $msg, $emsg,
                $this.$col
                    .get_mut(&($from, cookie))
                    .ok_or(FabricMsgError::CookieNotFound));
            sync.$f($db, &mut $this.state, $msg)
        } {
            $this.$col.remove(&($from, cookie)).unwrap();
        }
    }
}

impl VNode {
    pub fn new(storage_dir: &Path, num: u16) -> VNode {
        VNode {
            state: VNodeState {
                num: num,
                clock: BitmappedVersionVector::new(),
                peers: Default::default(),
                log: Default::default(),
                storage: Storage::open(storage_dir, num as i32, true).unwrap(),
                unflushed_coord_writes: 0,
            },
            migrations: Default::default(),
            syncs: Default::default(),
        }
    }

    fn cookie(&mut self) -> u64 {
        thread_rng().gen()
    }

    // HANDLERS
    pub fn handler_bootstrap_start(&mut self, db: &Database, from: NodeId,
                                   msg: FabricBootstrapStart) {
        let cookie = msg.cookie;
        let mut migration = Migration::Outgoing {
            vnode: self.state.num,
            cookie: cookie,
            iterator: self.state.storage.iter(),
            peer: from,
            count: 0,
        };
        migration.on_start(db, &mut self.state, msg);

        let p = self.migrations.insert((from, cookie), migration);
        assert!(p.is_none());
    }

    pub fn handler_bootstrap_send(&mut self, db: &Database, from: NodeId, msg: FabricBootstrapSend) {
        forward!(self, db, from, msg, FabricBootstrapFin, migrations, on_send);
    }

    pub fn handler_bootstrap_ack(&mut self, db: &Database, from: NodeId, msg: FabricBootstrapAck) {
        forward!(self, db, from, msg, FabricBootstrapFin, migrations, on_ack);
    }

    pub fn handler_bootstrap_fin(&mut self, db: &Database, from: NodeId, msg: FabricBootstrapFin) {
        forward!(self, db, from, msg, FabricBootstrapFin, migrations, on_fin);
    }

    pub fn handler_sync_send(&mut self, db: &Database, from: NodeId, msg: MsgSyncSend) {
        forward!(self, db, from, msg, MsgSyncFin, syncs, on_send);
    }

    pub fn handler_sync_ack(&mut self, db: &Database, from: NodeId, msg: MsgSyncAck) {
        forward!(self, db, from, msg, MsgSyncFin, syncs, on_ack);
    }

    pub fn handler_sync_fin(&mut self, db: &Database, from: NodeId, msg: MsgSyncFin) {
        forward!(self, db, from, msg, MsgSyncFin, syncs, on_fin);
    }

    /// //////
    pub fn start_migration(&mut self, db: &Database) {
        let cookie = self.cookie();
        let mut nodes = db.dht.nodes_for_vnode(self.state.num, db.replication_factor, false);
        thread_rng().shuffle(&mut nodes);
        for node in nodes {
            if node == db.dht.node() {
                continue;
            }
            let migration = Migration::Incomming {
                vnode: self.state.num,
                cookie: cookie,
                peer: node,
                count: 0,
            };

            db.fabric
                .send_message(node,
                              FabricBootstrapStart {
                                  cookie: cookie,
                                  vnode: self.state.num,
                              })
                .unwrap();

            let p = self.migrations.insert((node, cookie), migration);
            assert!(p.is_none());
            return;
        }
        unreachable!();
    }

    // pub fn start_sync(&mut self, db: &Database) {
    //     self.state.peers.iter().max_by_key(|&(&n, vp)|
    //         self.state.clock.get(n).map_or(0, |bv| bv.base()) - vp.knowledge
    //     )
    //     .map(|(&n, vp)| {
    //         let cookie = self.cookie();
    //         let sync = Synchronization::Incomming {
    //             peer: n,
    //             cookie: cookie,
    //             vnode: self.state.num,
    //             count: 0,
    //         };
    //
    //         db.fabric
    //             .send_message(n,
    //                           MsgSyncStart {
    //                               cookie: cookie,
    //                               vnode: self.state.num,
    //                           })
    //             .unwrap();
    //         let p = self.syncs.insert((n, cookie), sync);
    //         assert!(p.is_none());
    //         return;
    //     });
    // }
}

impl VNodeState {
    // STORAGE
    pub fn storage_get(&self, key: &[u8]) -> DottedCausalContainer<Vec<u8>> {
        let mut dcc = if let Some(bytes) = self.storage.get_vec(key) {
            bincode_serde::deserialize(&bytes).unwrap()
        } else {
            DottedCausalContainer::new()
        };
        dcc.fill(&self.clock);
        dcc
    }

    pub fn storage_set_local(&mut self, id: u64, key: &[u8], value_opt: Option<&[u8]>,
                             vv: &VersionVector)
                             -> DottedCausalContainer<Vec<u8>> {
        let mut dcc = self.storage_get(key);
        dcc.discard(vv);
        let dot = self.clock.event(id);
        if let Some(value) = value_opt {
            dcc.add(id, dot, value.into());
        }
        dcc.strip(&self.clock);

        if dcc.is_empty() {
            self.storage.del(key);
        } else {
            let mut bytes = Vec::new();
            bincode_serde::serialize_into(&mut bytes, &dcc, bincode::SizeLimit::Infinite).unwrap();
            self.storage.set(key, &bytes);
        }

        self.log.insert(dot, key.into());

        self.unflushed_coord_writes += 1;
        if self.unflushed_coord_writes >= PEER_LOG_SIZE {
            self.unflushed_coord_writes = 0;
            self.storage.sync();
        }

        dcc
    }

    pub fn storage_set_remote(&mut self, key: &[u8], mut new_dcc: DottedCausalContainer<Vec<u8>>,
                              log: Option<u64>) {
        let old_dcc = self.storage_get(key);
        new_dcc.add_to_bvv(&mut self.clock);
        new_dcc.sync(old_dcc);
        new_dcc.strip(&self.clock);

        if new_dcc.is_empty() {
            self.storage.del(key);
        } else {
            let mut bytes = Vec::new();
            bincode_serde::serialize_into(&mut bytes, &new_dcc, bincode::SizeLimit::Infinite)
                .unwrap();
            self.storage.set(key, &bytes);
        }

        if let Some(peer_id) = log {
            self.peers
                .entry(peer_id)
                .or_insert_with(|| VNodePeer::new())
                .log(self.clock.get(peer_id).unwrap().base(), key.into());
        }
    }
}

#[allow(unused_variables)]
impl Synchronization {
    fn outgoing_send(&mut self, db: &Database, state: &mut VNodeState) -> bool {
        match *self {
            Synchronization::Outgoing { peer,
                                        cookie,
                                        vnode,
                                        ref mut missing_dots,
                                        ref mut count,
                                        .. } => {
                let vnpeer = state.peers.get(&hash(peer)).unwrap();
                let kv_opt = missing_dots.next()
                    .and_then(|dot| vnpeer.get(dot))
                    .and_then(|k| state.storage.get_vec(&k).map(|v| (k, v)));
                if let Some((k, v)) = kv_opt {
                    db.fabric
                        .send_message(peer,
                                      MsgSyncSend {
                                          cookie: cookie,
                                          vnode: vnode,
                                          key: k.into(),
                                          container: bincode_serde::deserialize(&v).unwrap(),
                                      })
                        .unwrap();
                    *count += 1;
                } else {
                    debug!("[{}] synchronization of {} is done", db.dht.node(), vnode);
                    db.fabric
                        .send_message(peer,
                                      MsgSyncFin {
                                          cookie: cookie,
                                          vnode: vnode,
                                          result: Ok(()),
                                      })
                        .unwrap();
                }
                false
            }
            _ => unreachable!(),
        }
    }

    fn on_start(&mut self, db: &Database, state: &mut VNodeState, msg: MsgSyncStart) -> bool {
        match *self {
            Synchronization::Outgoing { .. } => self.outgoing_send(db, state),
            _ => unreachable!(),
        }
    }

    fn on_send(&mut self, db: &Database, state: &mut VNodeState, msg: MsgSyncSend) -> bool {
        match *self {
            Synchronization::Incomming { peer, vnode, ref mut count, .. } => {
                let mut bytes = Vec::new();
                bincode_serde::serialize_into(&mut bytes,
                                              &msg.container,
                                              bincode::SizeLimit::Infinite)
                    .unwrap();
                state.storage.set(&msg.key, &bytes);

                db.fabric
                    .send_message(peer,
                                  MsgSyncAck {
                                      cookie: msg.cookie,
                                      vnode: vnode,
                                  })
                    .unwrap();

                *count += 1;
                false
            }
            _ => unreachable!(),
        }
    }

    fn on_fin(&mut self, db: &Database, state: &mut VNodeState, msg: MsgSyncFin) -> bool {
        match *self {
            Synchronization::Incomming { peer, .. } => {
                // merge remote clock snapshot into our clocks
                state.storage.sync();
                // send it back as a form of ack-ack
                db.fabric.send_message(peer, msg).unwrap();
            }
            Synchronization::Outgoing { ref clock_in_peer, peer, .. } => {
                let vnpeer = state.peers.get_mut(&hash(peer)).unwrap();
                vnpeer.advance_knowledge(clock_in_peer.base());
            }
        }
        true
    }

    fn on_ack(&mut self, db: &Database, state: &mut VNodeState, msg: MsgSyncAck) -> bool {
        match *self {
            Synchronization::Outgoing { .. } => self.outgoing_send(db, state),
            _ => unreachable!(),
        }
    }
}

#[allow(unused_variables)]
impl Migration {
    fn outgoing_send(&mut self, db: &Database) -> bool {
        match *self {
            Migration::Outgoing { peer, cookie, vnode, ref mut iterator, ref mut count } => {
                let done = !iterator.iter(|k, v| {
                    db.fabric
                        .send_message(peer,
                                      FabricBootstrapSend {
                                          cookie: cookie,
                                          vnode: vnode,
                                          key: k.into(),
                                          container: bincode_serde::deserialize(v).unwrap(),
                                      })
                        .unwrap();
                    *count += 1;
                    false
                });
                if done {
                    debug!("[{}] sync of {} is done", db.dht.node(), vnode);
                    db.fabric
                        .send_message(peer,
                                      FabricBootstrapFin {
                                          cookie: cookie,
                                          vnode: vnode,
                                          result: Ok(()),
                                      })
                        .unwrap();
                }
                false
            }
            _ => unreachable!(),
        }
    }

    fn on_start(&mut self, db: &Database, state: &mut VNodeState, msg: FabricBootstrapStart) -> bool {
        match *self {
            Migration::Outgoing { .. } => self.outgoing_send(db),
            _ => unreachable!(),
        }
    }

    fn on_send(&mut self, db: &Database, state: &mut VNodeState, msg: FabricBootstrapSend) -> bool {
        match *self {
            Migration::Incomming { vnode, peer, ref mut count, .. } => {
                state.storage_set_remote(&msg.key, msg.container, None);
                db.fabric
                    .send_message(peer,
                                  FabricBootstrapAck {
                                      cookie: msg.cookie,
                                      vnode: vnode,
                                  })
                    .unwrap();

                *count += 1;
                false
            }
            _ => unreachable!(),
        }
    }

    fn on_fin(&mut self, db: &Database, state: &mut VNodeState, msg: FabricBootstrapFin) -> bool {
        match *self {
            Migration::Incomming { peer, .. } => {
                state.storage.sync();
                // db.dht.promote_pending_node(vnode: u16, node: NodeId)
                // send it back as a form of ack-ack
                db.fabric.send_message(peer, msg).unwrap();
            }
            Migration::Outgoing { .. } => (),
        }
        true
    }

    fn on_ack(&mut self, db: &Database, state: &mut VNodeState, msg: FabricBootstrapAck) -> bool {
        match *self {
            Migration::Outgoing { .. } => self.outgoing_send(db),
            _ => unreachable!(),
        }
    }
}
<|endoftext|>


<commit_before>use numeric::LNumeric;
use std::fmt;
use std::rc::Rc;

#[deriving(PartialEq)]
pub enum LDatum<T> {
    LIdent(String),
    LString(String),
    LChar(char),
    LBool(bool),
    LNum(LNumeric),
    LCons(Rc<LDatum<T>>, Rc<LDatum<T>>),
    LNil,
    LVector(Rc<Vec<Rc<LDatum<T>>>>),
    LExt(T),
}

#[deriving(PartialEq)]
pub enum Quotation
{
    Quote,
    QuasiQuote,
    Unquote,
    UnquoteSplicing,
}

impl<T: fmt::Show> fmt::Show for LDatum<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &LIdent(ref s) => write!(f, "{}", s),
            &LString(ref s) => write!(f, "\"{}\"", s.escape_default()),
            &LChar(' ') => write!(f, "#\\space"),
            &LChar('\n') => write!(f, "#\\newline"),
            &LChar(c) => write!(f, "#\\{:c}", c),
            &LBool(true) => write!(f, "#t"),
            &LBool(false) => write!(f, "#f"),
            &LNum(ref x) => write!(f, "{}", x),
            &LCons(ref head, ref tail) => {
                match is_quote(head.deref(), tail.deref()) {
                    Some((name, v)) => {
                        let prefix = match name {
                            Quote => "\'",
                            Unquote => ",",
                            UnquoteSplicing => ",@",
                            QuasiQuote => "`",
                        };
                        write!(f, "{}{}", prefix, v)
                    },
                    None => {
                        try!(write!(f, "({}", *head));
                        write_list(f, tail.deref())
                    },
                }
            },
            &LNil => write!(f, "()"),
            &LVector(ref v) => match v.as_slice() {
                [] => write!(f, "#()"),
                [ref head, .. ref tail] => {
                    try!(write!(f, "{}", head))
                    for x in tail.iter() {
                        try!(write!(f, " {}", x))
                    }
                    Ok(())
                }
            },
            &LExt(ref v) => {
                write!(f, "{}", v)
            },
        }
    }
}

impl<T> LDatum<T> {
    pub fn to_list(&self) -> Option<Vec<Rc<LDatum<T>>>> {
        match self {
            &LCons(ref h, ref t) => datum_to_list(h.clone(), t.clone()),
            &LNil => Some(vec![]),
            _ => None,
        }
    }

    pub fn from_list(list: &[Rc<LDatum<T>>]) -> Rc<LDatum<T>> {
        match list {
            [] => Rc::new(LNil),
            [ref h, ..ref t] => Rc::new(LCons(h.clone(), LDatum::from_list(*t))),
        }
    }

    pub fn append(&self, other: Rc<LDatum<T>>) -> Option<Rc<LDatum<T>>> {
        match self {
            &LNil => Some(other),
            &LCons(ref h, ref t) => t.append(other).map(|ts| { Rc::new(LCons(h.clone(), ts)) }),
            _ => None,
        }
    }
}

fn datum_to_list<T>(head: Rc<LDatum<T>>, tail: Rc<LDatum<T>>) -> Option<Vec<Rc<LDatum<T>>>> {
    let mut x = &tail;
    let mut list = vec![head.clone()];

    loop {
        match x.deref() {
            &LCons(ref h, ref t) => {
                list.push(h.clone());
                x = t;
            },
            &LNil => break,
            _ => return None,
        }
    }

    Some(list)
}

pub fn is_quote<T>(head: &LDatum<T>, tail: &LDatum<T>) -> Option<(Quotation, Rc<LDatum<T>>)> {
    match head {
        &LIdent(ref name) =>
            match tail {
                &LCons(ref v, ref t) => match *t.deref() {
                    LNil =>
                        if name.as_slice() == "quote" {
                            Some((Quote, v.clone()))
                        } else if name.as_slice() == "quasiquote" {
                            Some((QuasiQuote, v.clone()))
                        } else if name.as_slice() == "unquote" {
                            Some((Unquote, v.clone()))
                        } else if name.as_slice() == "unquote-splicing" {
                            Some((UnquoteSplicing, v.clone()))
                        } else {
                            None
                        },
                    _ => None
                },
                _ => None
            },
        _ =>
            None,
    }
}

fn write_list<T: fmt::Show>(f: &mut fmt::Formatter, v: &LDatum<T>) -> fmt::Result {
    match v {
        &LCons(ref head, ref tail) => {
            try!(write!(f, " {}", head));
            write_list(f, tail.deref())
        },
        &LNil => write!(f, ")"),
        _ => write!(f, " . {})", v)
    }
}
<commit_msg>Remove slice matching pattern<commit_after>use numeric::LNumeric;
use std::fmt;
use std::rc::Rc;

#[deriving(PartialEq)]
pub enum LDatum<T> {
    LIdent(String),
    LString(String),
    LChar(char),
    LBool(bool),
    LNum(LNumeric),
    LCons(Rc<LDatum<T>>, Rc<LDatum<T>>),
    LNil,
    LVector(Rc<Vec<Rc<LDatum<T>>>>),
    LExt(T),
}

#[deriving(PartialEq)]
pub enum Quotation
{
    Quote,
    QuasiQuote,
    Unquote,
    UnquoteSplicing,
}

impl<T: fmt::Show> fmt::Show for LDatum<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &LIdent(ref s) => write!(f, "{}", s),
            &LString(ref s) => write!(f, "\"{}\"", s.escape_default()),
            &LChar(' ') => write!(f, "#\\space"),
            &LChar('\n') => write!(f, "#\\newline"),
            &LChar(c) => write!(f, "#\\{:c}", c),
            &LBool(true) => write!(f, "#t"),
            &LBool(false) => write!(f, "#f"),
            &LNum(ref x) => write!(f, "{}", x),
            &LCons(ref head, ref tail) => {
                match is_quote(head.deref(), tail.deref()) {
                    Some((name, v)) => {
                        let prefix = match name {
                            Quote => "\'",
                            Unquote => ",",
                            UnquoteSplicing => ",@",
                            QuasiQuote => "`",
                        };
                        write!(f, "{}{}", prefix, v)
                    },
                    None => {
                        try!(write!(f, "({}", *head));
                        write_list(f, tail.deref())
                    },
                }
            },
            &LNil => write!(f, "()"),
            &LVector(ref v) => match v.as_slice() {
                [] => write!(f, "#()"),
                slice => {
                    try!(write!(f, "{}", slice.head()));
                    for x in slice.tail().iter() {
                        try!(write!(f, " {}", x))
                    }
                    Ok(())
                }
            },
            &LExt(ref v) => {
                write!(f, "{}", v)
            },
        }
    }
}

impl<T> LDatum<T> {
    pub fn to_list(&self) -> Option<Vec<Rc<LDatum<T>>>> {
        match self {
            &LCons(ref h, ref t) => datum_to_list(h.clone(), t.clone()),
            &LNil => Some(vec![]),
            _ => None,
        }
    }

    pub fn from_list(list: &[Rc<LDatum<T>>]) -> Rc<LDatum<T>> {
        match list {
            [] => Rc::new(LNil),
            _ => Rc::new(LCons(list.head().unwrap().clone(), LDatum::from_list(list.tail()))),
        }
    }

    pub fn append(&self, other: Rc<LDatum<T>>) -> Option<Rc<LDatum<T>>> {
        match self {
            &LNil => Some(other),
            &LCons(ref h, ref t) => t.append(other).map(|ts| { Rc::new(LCons(h.clone(), ts)) }),
            _ => None,
        }
    }
}

fn datum_to_list<T>(head: Rc<LDatum<T>>, tail: Rc<LDatum<T>>) -> Option<Vec<Rc<LDatum<T>>>> {
    let mut x = &tail;
    let mut list = vec![head.clone()];

    loop {
        match x.deref() {
            &LCons(ref h, ref t) => {
                list.push(h.clone());
                x = t;
            },
            &LNil => break,
            _ => return None,
        }
    }

    Some(list)
}

pub fn is_quote<T>(head: &LDatum<T>, tail: &LDatum<T>) -> Option<(Quotation, Rc<LDatum<T>>)> {
    match head {
        &LIdent(ref name) =>
            match tail {
                &LCons(ref v, ref t) => match *t.deref() {
                    LNil =>
                        if name.as_slice() == "quote" {
                            Some((Quote, v.clone()))
                        } else if name.as_slice() == "quasiquote" {
                            Some((QuasiQuote, v.clone()))
                        } else if name.as_slice() == "unquote" {
                            Some((Unquote, v.clone()))
                        } else if name.as_slice() == "unquote-splicing" {
                            Some((UnquoteSplicing, v.clone()))
                        } else {
                            None
                        },
                    _ => None
                },
                _ => None
            },
        _ =>
            None,
    }
}

fn write_list<T: fmt::Show>(f: &mut fmt::Formatter, v: &LDatum<T>) -> fmt::Result {
    match v {
        &LCons(ref head, ref tail) => {
            try!(write!(f, " {}", head));
            write_list(f, tail.deref())
        },
        &LNil => write!(f, ")"),
        _ => write!(f, " . {})", v)
    }
}
<|endoftext|>


<commit_before>use std::fmt;

/// Errors that can be returned from various operations
///
pub enum Error {
    /// Returned if menu Menu function isn't supported
    MenusNotSupported,
    /// Menu already exists
    MenuExists(String),
    /// Menu already exists
    WindowCreate(String),
    /// Unable to Update
    UpdateFailed(String),
}

impl fmt::Debug for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Error::MenusNotSupported => write!(formatter, "Menus not supported"),
            Error::MenuExists(_) => write!(formatter, "Menu already exists"),
            Error::WindowCreate(_) => write!(formatter, "Failed to create window"),
            Error::UpdateFailed(_) => write!(formatter, "Failed to Update"),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::MenusNotSupported => write!(fmt, "{:?}", self),
            Error::MenuExists(ref e) => write!(fmt, "{:?} {:?}", self, e),
            Error::WindowCreate(ref e) => write!(fmt, "{:?} {:?}", self, e),
            Error::UpdateFailed(ref e) => write!(fmt, "{:?} {:?}", self, e),
        }
    }
}
<commit_msg>Implemented std::error::Error for minifb::Error (#168)<commit_after>use std::error::Error as StdError;
use std::fmt;

/// Errors that can be returned from various operations
///
pub enum Error {
    /// Returned if menu Menu function isn't supported
    MenusNotSupported,
    /// Menu already exists
    MenuExists(String),
    /// Menu already exists
    WindowCreate(String),
    /// Unable to Update
    UpdateFailed(String),
}

impl fmt::Debug for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Error::MenusNotSupported => write!(formatter, "Menus not supported"),
            Error::MenuExists(_) => write!(formatter, "Menu already exists"),
            Error::WindowCreate(_) => write!(formatter, "Failed to create window"),
            Error::UpdateFailed(_) => write!(formatter, "Failed to Update"),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::MenusNotSupported => write!(fmt, "{:?}", self),
            Error::MenuExists(ref e) => write!(fmt, "{:?} {:?}", self, e),
            Error::WindowCreate(ref e) => write!(fmt, "{:?} {:?}", self, e),
            Error::UpdateFailed(ref e) => write!(fmt, "{:?} {:?}", self, e),
        }
    }
}

impl StdError for Error {}
<|endoftext|>


<commit_before>//! Encoding and decoding of the (63, 16, 23) BCH code described by P25.
//!
//! These algorithms are derived from *Coding Theory and Cryptography: The Essentials*,
//! Hankerson, Hoffman, et al, 2000.

use std;

use coding::galois::{GaloisField, P25Field, P25Codeword, Polynomial, PolynomialCoefs};
use coding::bmcf;

/// Encode the given 16 data bits into a 64-bit codeword.
pub fn encode(word: u16) -> u64 {
    matrix_mul_systematic!(word, GEN, u64)
}

/// Try to decode the given 64-bit word to the nearest codeword, correcting up to 11
/// bit errors.
///
/// If decoding was successful, return `Some((data, err))`, where `data` is the 16 data
/// bits and `err` is the number of bits corrected. Otherwise, return `None` to indicate
/// an unrecoverable error.
pub fn decode(bits: u64) -> Option<(u16, usize)> {
    // The BCH code is only over the first 63 bits, so strip off the P25 parity bit.
    let word = bits >> 1;

    bmcf::Errors::new(syndromes(word)).map(|(nerr, errs)| {
        // Flip all error bits.
        let fixed = errs.fold(word, |w, (loc, pat)| {
            assert!(pat.power().unwrap() == 0);
            w ^ 1 << loc
        });

        // Strip off the parity bits.
        ((fixed >> 47) as u16, nerr)
    })
}

/// Generator matrix from P25, transformed for more efficient codeword generation.
const GEN: &'static [u16] = &[
    0b1110110001000111,
    0b1001101001100100,
    0b0100110100110010,
    0b0010011010011001,
    0b1111111100001011,
    0b1001001111000010,
    0b0100100111100001,
    0b1100100010110111,
    0b1000100000011100,
    0b0100010000001110,
    0b0010001000000111,
    0b1111110101000100,
    0b0111111010100010,
    0b0011111101010001,
    0b1111001111101111,
    0b1001010110110000,
    0b0100101011011000,
    0b0010010101101100,
    0b0001001010110110,
    0b0000100101011011,
    0b1110100011101010,
    0b0111010001110101,
    0b1101011001111101,
    0b1000011101111001,
    0b1010111111111011,
    0b1011101110111010,
    0b0101110111011101,
    0b1100001010101001,
    0b1000110100010011,
    0b1010101011001110,
    0b0101010101100111,
    0b1100011011110100,
    0b0110001101111010,
    0b0011000110111101,
    0b1111010010011001,
    0b1001011000001011,
    0b1010011101000010,
    0b0101001110100001,
    0b1100010110010111,
    0b1000111010001100,
    0b0100011101000110,
    0b0010001110100011,
    0b1111110110010110,
    0b0111111011001011,
    0b1101001100100010,
    0b0110100110010001,
    0b1101100010001111,
    0b0000000000000011,
];

/// Polynomial coefficients for BCH decoding.
impl_polynomial_coefs!(BCHCoefs, 23);

/// Polynomial with BCH coefficients.
type BCHPolynomial = Polynomial<BCHCoefs>;

/// Generate the syndrome polynomial s(x) from the given received word r(x).
///
/// The resulting polynomial has the form s(x) = s1 + s2x + ··· +
/// s2tx2t, where si = r(αi).
fn syndromes(word: u64) -> BCHPolynomial {
    BCHPolynomial::new((1...BCHCoefs::syndromes()).map(|p| {
        // Compute r(α^p) with the polynomial representation of the bitmap. The LSB of
        // `word` maps to the coefficient of the degree-0 term.
        (0..P25Field::size()).fold(P25Codeword::default(), |s, b| {
            if word >> b & 1 == 0 {
                s
            } else {
                s + P25Codeword::for_power(b * p)
            }
        })
    }))
}

#[cfg(test)]
mod test {
    use std;
    use super::*;
    use super::{syndromes, BCHCoefs};
    use coding::galois::{PolynomialCoefs, P25Codeword, Polynomial};

    impl_polynomial_coefs!(TestCoefs, 23, 50);
    type TestPolynomial = Polynomial<TestCoefs>;

    #[test]
    fn validate_coefs() {
        BCHCoefs::default().validate();
    }

    #[test]
    fn verify_gen() {
        // Verify construction of BCH generator polynomial g(x).

        let p = Polynomial::<TestCoefs>::new([
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::default(),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::default(),
            P25Codeword::default(),
            P25Codeword::default(),
            P25Codeword::for_power(0),
        ].iter().cloned());

        assert_eq!(p.degree().unwrap(), 47);

        let gen = 0o6331_1413_6723_5453u64;

        for i in 0...47 {
            let coef = gen >> i & 1;

            assert_eq!(p[i].power(), if coef == 0 {
                None
            } else {
                Some(0)
            });
        }
    }

    #[test]
    fn test_encode() {
        assert_eq!(encode(0b1111111100000000), 0b1111111100000000100100110001000011000010001100000110100001101000);
        assert_eq!(encode(0b0011)&1, 0);
        assert_eq!(encode(0b0101)&1, 1);
        assert_eq!(encode(0b1010)&1, 1);
        assert_eq!(encode(0b1100)&1, 0);
        assert_eq!(encode(0b1111)&1, 0);
    }

    #[test]
    fn test_syndromes() {
        let w = encode(0b1111111100000000)>>1;

        assert_eq!(syndromes(w).degree(), None);
        assert_eq!(syndromes(w ^ 1<<60).degree().unwrap(), 21);
    }

    #[test]
    fn test_decode() {
        assert!(decode(encode(0b0000111100001111) ^ 1<<63).unwrap() ==
                (0b0000111100001111, 1));

        assert!(decode(encode(0b1100011111111111) ^ 1).unwrap() ==
                (0b1100011111111111, 0));

        assert!(decode(encode(0b1111111100000000) ^ 0b11010011<<30).unwrap() ==
                (0b1111111100000000, 5));

        assert!(decode(encode(0b1101101101010001) ^ (1<<63 | 1)).unwrap() ==
                (0b1101101101010001, 1));

        assert!(decode(encode(0b1111111111111111) ^ 0b11111111111).unwrap() ==
                (0b1111111111111111, 10));

        assert!(decode(encode(0b0000000000000000) ^ 0b11111111111).unwrap() ==
                (0b0000000000000000, 10));

        assert!(decode(encode(0b0000111110000000) ^ 0b111111111110).unwrap() ==
                (0b0000111110000000, 11));

        assert!(decode(encode(0b0000111110000000) ^ 0b111111111110).unwrap() ==
                (0b0000111110000000, 11));

        assert!(decode(encode(0b0000111110001010) ^ 0b1111111111110).is_none());
        assert!(decode(encode(0b0000001111111111) ^ 0b11111111111111111111110).is_none());
        assert!(decode(encode(0b0000001111111111) ^
                       0b00100101010101000010001100100010011111111110).is_none());

        for i in 0..1u32<<17 {
            assert_eq!(decode(encode(i as u16)).unwrap().0, i as u16);
        }
    }
}
<commit_msg>s/BCHPolynomial/BchPolynomial/<commit_after>//! Encoding and decoding of the (63, 16, 23) BCH code described by P25.
//!
//! These algorithms are derived from *Coding Theory and Cryptography: The Essentials*,
//! Hankerson, Hoffman, et al, 2000.

use std;

use coding::galois::{GaloisField, P25Field, P25Codeword, Polynomial, PolynomialCoefs};
use coding::bmcf;

/// Encode the given 16 data bits into a 64-bit codeword.
pub fn encode(word: u16) -> u64 {
    matrix_mul_systematic!(word, GEN, u64)
}

/// Try to decode the given 64-bit word to the nearest codeword, correcting up to 11
/// bit errors.
///
/// If decoding was successful, return `Some((data, err))`, where `data` is the 16 data
/// bits and `err` is the number of bits corrected. Otherwise, return `None` to indicate
/// an unrecoverable error.
pub fn decode(bits: u64) -> Option<(u16, usize)> {
    // The BCH code is only over the first 63 bits, so strip off the P25 parity bit.
    let word = bits >> 1;

    bmcf::Errors::new(syndromes(word)).map(|(nerr, errs)| {
        // Flip all error bits.
        let fixed = errs.fold(word, |w, (loc, pat)| {
            assert!(pat.power().unwrap() == 0);
            w ^ 1 << loc
        });

        // Strip off the parity bits.
        ((fixed >> 47) as u16, nerr)
    })
}

/// Generator matrix from P25, transformed for more efficient codeword generation.
const GEN: &'static [u16] = &[
    0b1110110001000111,
    0b1001101001100100,
    0b0100110100110010,
    0b0010011010011001,
    0b1111111100001011,
    0b1001001111000010,
    0b0100100111100001,
    0b1100100010110111,
    0b1000100000011100,
    0b0100010000001110,
    0b0010001000000111,
    0b1111110101000100,
    0b0111111010100010,
    0b0011111101010001,
    0b1111001111101111,
    0b1001010110110000,
    0b0100101011011000,
    0b0010010101101100,
    0b0001001010110110,
    0b0000100101011011,
    0b1110100011101010,
    0b0111010001110101,
    0b1101011001111101,
    0b1000011101111001,
    0b1010111111111011,
    0b1011101110111010,
    0b0101110111011101,
    0b1100001010101001,
    0b1000110100010011,
    0b1010101011001110,
    0b0101010101100111,
    0b1100011011110100,
    0b0110001101111010,
    0b0011000110111101,
    0b1111010010011001,
    0b1001011000001011,
    0b1010011101000010,
    0b0101001110100001,
    0b1100010110010111,
    0b1000111010001100,
    0b0100011101000110,
    0b0010001110100011,
    0b1111110110010110,
    0b0111111011001011,
    0b1101001100100010,
    0b0110100110010001,
    0b1101100010001111,
    0b0000000000000011,
];

/// Polynomial coefficients for BCH decoding.
impl_polynomial_coefs!(BCHCoefs, 23);

/// Polynomial with BCH coefficients.
type BchPolynomial = Polynomial<BCHCoefs>;

/// Generate the syndrome polynomial s(x) from the given received word r(x).
///
/// The resulting polynomial has the form s(x) = s1 + s2x + ··· +
/// s2tx2t, where si = r(αi).
fn syndromes(word: u64) -> BchPolynomial {
    BchPolynomial::new((1...BCHCoefs::syndromes()).map(|p| {
        // Compute r(α^p) with the polynomial representation of the bitmap. The LSB of
        // `word` maps to the coefficient of the degree-0 term.
        (0..P25Field::size()).fold(P25Codeword::default(), |s, b| {
            if word >> b & 1 == 0 {
                s
            } else {
                s + P25Codeword::for_power(b * p)
            }
        })
    }))
}

#[cfg(test)]
mod test {
    use std;
    use super::*;
    use super::{syndromes, BCHCoefs};
    use coding::galois::{PolynomialCoefs, P25Codeword, Polynomial};

    impl_polynomial_coefs!(TestCoefs, 23, 50);
    type TestPolynomial = Polynomial<TestCoefs>;

    #[test]
    fn validate_coefs() {
        BCHCoefs::default().validate();
    }

    #[test]
    fn verify_gen() {
        // Verify construction of BCH generator polynomial g(x).

        let p = Polynomial::<TestCoefs>::new([
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::default(),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::for_power(0),
        ].iter().cloned()) * Polynomial::new([
            P25Codeword::for_power(0),
            P25Codeword::for_power(0),
            P25Codeword::default(),
            P25Codeword::default(),
            P25Codeword::default(),
            P25Codeword::default(),
            P25Codeword::for_power(0),
        ].iter().cloned());

        assert_eq!(p.degree().unwrap(), 47);

        let gen = 0o6331_1413_6723_5453u64;

        for i in 0...47 {
            let coef = gen >> i & 1;

            assert_eq!(p[i].power(), if coef == 0 {
                None
            } else {
                Some(0)
            });
        }
    }

    #[test]
    fn test_encode() {
        assert_eq!(encode(0b1111111100000000), 0b1111111100000000100100110001000011000010001100000110100001101000);
        assert_eq!(encode(0b0011)&1, 0);
        assert_eq!(encode(0b0101)&1, 1);
        assert_eq!(encode(0b1010)&1, 1);
        assert_eq!(encode(0b1100)&1, 0);
        assert_eq!(encode(0b1111)&1, 0);
    }

    #[test]
    fn test_syndromes() {
        let w = encode(0b1111111100000000)>>1;

        assert_eq!(syndromes(w).degree(), None);
        assert_eq!(syndromes(w ^ 1<<60).degree().unwrap(), 21);
    }

    #[test]
    fn test_decode() {
        assert!(decode(encode(0b0000111100001111) ^ 1<<63).unwrap() ==
                (0b0000111100001111, 1));

        assert!(decode(encode(0b1100011111111111) ^ 1).unwrap() ==
                (0b1100011111111111, 0));

        assert!(decode(encode(0b1111111100000000) ^ 0b11010011<<30).unwrap() ==
                (0b1111111100000000, 5));

        assert!(decode(encode(0b1101101101010001) ^ (1<<63 | 1)).unwrap() ==
                (0b1101101101010001, 1));

        assert!(decode(encode(0b1111111111111111) ^ 0b11111111111).unwrap() ==
                (0b1111111111111111, 10));

        assert!(decode(encode(0b0000000000000000) ^ 0b11111111111).unwrap() ==
                (0b0000000000000000, 10));

        assert!(decode(encode(0b0000111110000000) ^ 0b111111111110).unwrap() ==
                (0b0000111110000000, 11));

        assert!(decode(encode(0b0000111110000000) ^ 0b111111111110).unwrap() ==
                (0b0000111110000000, 11));

        assert!(decode(encode(0b0000111110001010) ^ 0b1111111111110).is_none());
        assert!(decode(encode(0b0000001111111111) ^ 0b11111111111111111111110).is_none());
        assert!(decode(encode(0b0000001111111111) ^
                       0b00100101010101000010001100100010011111111110).is_none());

        for i in 0..1u32<<17 {
            assert_eq!(decode(encode(i as u16)).unwrap().0, i as u16);
        }
    }
}
<|endoftext|>


<commit_before>use crate::{
    channel::Channel,
    channels::Channels,
    configuration::Configuration,
    connection_closer::ConnectionCloser,
    connection_properties::ConnectionProperties,
    connection_status::{ConnectionState, ConnectionStatus, ConnectionStep},
    executor::{DefaultExecutor, Executor},
    frames::Frames,
    internal_rpc::{InternalRPC, InternalRPCHandle},
    io_loop::IoLoop,
    reactor::DefaultReactorBuilder,
    socket_state::{SocketState, SocketStateHandle},
    tcp::{AMQPUriTcpExt, HandshakeResult, TLSConfig},
    thread::ThreadHandle,
    types::ShortUInt,
    uri::AMQPUri,
    Error, Promise, PromiseChain, Result,
};
use amq_protocol::frame::{AMQPFrame, ProtocolVersion};
use log::{log_enabled, Level::Trace};
use std::{fmt, io, sync::Arc};

pub struct Connection {
    configuration: Configuration,
    status: ConnectionStatus,
    channels: Channels,
    io_loop: ThreadHandle,
    closer: Arc<ConnectionCloser>,
}

impl Connection {
    fn new(
        waker: SocketStateHandle,
        internal_rpc: InternalRPCHandle,
        frames: Frames,
        executor: Arc<dyn Executor>,
    ) -> Self {
        let configuration = Configuration::default();
        let status = ConnectionStatus::default();
        let channels = Channels::new(
            configuration.clone(),
            status.clone(),
            waker,
            internal_rpc.clone(),
            frames,
            executor,
        );
        let closer = Arc::new(ConnectionCloser::new(status.clone(), internal_rpc));
        let connection = Self {
            configuration,
            status,
            channels,
            io_loop: ThreadHandle::default(),
            closer,
        };

        connection.channels.create_zero();
        connection
    }

    /// Connect to an AMQP Server
    pub fn connect(uri: &str, options: ConnectionProperties) -> PromiseChain<Connection> {
        Connect::connect(uri, options, TLSConfig::default())
    }

    /// Connect to an AMQP Server
    pub fn connect_with_config(
        uri: &str,
        options: ConnectionProperties,
        config: TLSConfig<'_, '_, '_>,
    ) -> PromiseChain<Connection> {
        Connect::connect(uri, options, config)
    }

    /// Connect to an AMQP Server
    pub fn connect_uri(uri: AMQPUri, options: ConnectionProperties) -> PromiseChain<Connection> {
        Connect::connect(uri, options, TLSConfig::default())
    }

    /// Connect to an AMQP Server
    pub fn connect_uri_with_identity(
        uri: AMQPUri,
        options: ConnectionProperties,
        config: TLSConfig<'_, '_, '_>,
    ) -> PromiseChain<Connection> {
        Connect::connect(uri, options, config)
    }

    pub fn create_channel(&self) -> PromiseChain<Channel> {
        if !self.status.connected() {
            return PromiseChain::new_with_data(Err(Error::InvalidConnectionState(
                self.status.state(),
            )));
        }
        match self.channels.create(self.closer.clone()) {
            Ok(channel) => self
                .channels
                .with_channel(channel.id(), |c| c.channel_open(channel))
                .expect("internal error creating channel"),
            Err(error) => PromiseChain::new_with_data(Err(error)),
        }
    }

    /// Block current thread while the connection is still active.
    /// This is useful when you only have a consumer and nothing else keeping your application
    /// "alive".
    pub fn run(&self) -> Result<()> {
        self.io_loop.wait("io loop")
    }

    pub fn on_error<E: FnMut(Error) + Send + 'static>(&self, handler: E) {
        self.channels.set_error_handler(handler);
    }

    pub fn configuration(&self) -> &Configuration {
        &self.configuration
    }

    pub fn status(&self) -> &ConnectionStatus {
        &self.status
    }

    pub fn close(&self, reply_code: ShortUInt, reply_text: &str) -> Promise<()> {
        self.channels
            .with_channel(0, |channel0| {
                channel0.connection_close(reply_code, reply_text, 0, 0)
            })
            .unwrap_or_else(|| Promise::new_with_data(Ok(())))
    }

    /// Block all consumers and publishers on this connection
    pub fn block(&self, reason: &str) -> Promise<()> {
        self.channels
            .with_channel(0, |channel0| channel0.connection_blocked(reason))
            .unwrap_or_else(|| {
                Promise::new_with_data(Err(Error::InvalidConnectionState(self.status.state())))
            })
    }

    /// Unblock all consumers and publishers on this connection
    pub fn unblock(&self) -> Promise<()> {
        self.channels
            .with_channel(0, |channel0| channel0.connection_unblocked())
            .unwrap_or_else(|| {
                Promise::new_with_data(Err(Error::InvalidConnectionState(self.status.state())))
            })
    }

    /// Update the secret used by some authentication module such as OAuth2
    pub fn update_secret(&self, new_secret: &str, reason: &str) -> Promise<()> {
        self.channels
            .with_channel(0, |channel0| {
                channel0.connection_update_secret(new_secret, reason)
            })
            .unwrap_or_else(|| {
                Promise::new_with_data(Err(Error::InvalidConnectionState(self.status.state())))
            })
    }

    pub fn connector(
        mut options: ConnectionProperties,
    ) -> impl FnOnce(AMQPUri, HandshakeResult) -> PromiseChain<Connection> + 'static {
        move |uri, handshake_result| {
            let executor = options
                .executor
                .take()
                .unwrap_or_else(|| Arc::new(DefaultExecutor::default()));
            let reactor_builder = options
                .reactor_builder
                .take()
                .unwrap_or_else(|| Arc::new(DefaultReactorBuilder));
            let socket_state = SocketState::default();
            let waker = socket_state.handle();
            let internal_rpc = InternalRPC::new(executor.clone(), waker.clone());
            let frames = Frames::default();
            let conn = Connection::new(waker, internal_rpc.handle(), frames.clone(), executor);
            let status = conn.status.clone();
            let configuration = conn.configuration.clone();
            status.set_vhost(&uri.vhost);
            status.set_username(&uri.authority.userinfo.username);
            if let Some(frame_max) = uri.query.frame_max {
                configuration.set_frame_max(frame_max);
            }
            if let Some(channel_max) = uri.query.channel_max {
                configuration.set_channel_max(channel_max);
            }
            if let Some(heartbeat) = uri.query.heartbeat {
                configuration.set_heartbeat(heartbeat);
            }
            let (promise, resolver) = Promise::new();
            if log_enabled!(Trace) {
                promise.set_marker("ProtocolHeader".into());
            }
            let channels = conn.channels.clone();
            channels.with_channel(0, |channel0| {
                channel0.send_frame(
                    AMQPFrame::ProtocolHeader(ProtocolVersion::amqp_0_9_1()),
                    resolver,
                    None,
                )
            });
            let (promise, resolver) = PromiseChain::after(promise);
            if log_enabled!(Trace) {
                promise.set_marker("ProtocolHeader.Ok".into());
            }
            let io_loop_handle = conn.io_loop.clone();
            status.set_state(ConnectionState::Connecting);
            status.set_connection_step(ConnectionStep::ProtocolHeader(
                resolver,
                conn,
                uri.authority.userinfo.into(),
                uri.query.auth_mechanism.unwrap_or_default(),
                options,
            ));
            IoLoop::new(
                status,
                configuration,
                channels,
                internal_rpc,
                frames,
                socket_state,
                io_loop_handle,
                handshake_result,
                &*reactor_builder,
            )
            .and_then(IoLoop::start)
            .map(|()| promise)
            .unwrap_or_else(|err| PromiseChain::new_with_data(Err(err)))
        }
    }
}

impl fmt::Debug for Connection {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Connection")
            .field("configuration", &self.configuration)
            .field("status", &self.status)
            .field("channels", &self.channels)
            .finish()
    }
}

/// Trait providing a method to connect to an AMQP server
pub trait Connect {
    /// connect to an AMQP server
    fn connect(
        self,
        options: ConnectionProperties,
        config: TLSConfig<'_, '_, '_>,
    ) -> PromiseChain<Connection>;
}

impl Connect for AMQPUri {
    fn connect(
        self,
        options: ConnectionProperties,
        config: TLSConfig<'_, '_, '_>,
    ) -> PromiseChain<Connection> {
        let stream = AMQPUriTcpExt::connect_with_config(&self, config);
        Connection::connector(options)(self, stream)
    }
}

impl Connect for &str {
    fn connect(
        self,
        options: ConnectionProperties,
        config: TLSConfig<'_, '_, '_>,
    ) -> PromiseChain<Connection> {
        match self.parse::<AMQPUri>() {
            Ok(uri) => Connect::connect(uri, options, config),
            Err(err) => {
                PromiseChain::new_with_data(Err(io::Error::new(io::ErrorKind::Other, err).into()))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use env_logger;

    use super::*;
    use crate::channel_receiver_state::ChannelReceiverState;
    use crate::channel_status::ChannelState;
    use crate::types::ShortString;
    use crate::BasicProperties;
    use amq_protocol::frame::AMQPContentHeader;
    use amq_protocol::protocol::{basic, AMQPClass};

    #[test]
    fn basic_consume_small_payload() {
        let _ = env_logger::try_init();

        use crate::consumer::Consumer;
        use crate::queue::{Queue, QueueState};

        // Bootstrap connection state to a consuming state
        let executor = Arc::new(DefaultExecutor::default());
        let socket_state = SocketState::default();
        let waker = socket_state.handle();
        let internal_rpc = InternalRPC::new(executor.clone(), waker.clone());
        let conn = Connection::new(
            waker,
            internal_rpc.handle(),
            Frames::default(),
            executor.clone(),
        );
        conn.status.set_state(ConnectionState::Connected);
        conn.configuration.set_channel_max(2047);
        let channel = conn.channels.create(conn.closer.clone()).unwrap();
        channel.set_state(ChannelState::Connected);
        let queue_name = ShortString::from("consumed");
        let mut queue: QueueState = Queue::new(queue_name.clone(), 0, 0).into();
        let consumer_tag = ShortString::from("consumer-tag");
        let consumer = Consumer::new(consumer_tag.clone(), executor);
        queue.register_consumer(consumer_tag.clone(), consumer);
        conn.channels
            .with_channel(channel.id(), |c| c.register_queue(queue));
        // Now test the state machine behaviour
        {
            let method = AMQPClass::Basic(basic::AMQPMethod::Deliver(basic::Deliver {
                consumer_tag: consumer_tag.clone(),
                delivery_tag: 1,
                redelivered: false,
                exchange: "".into(),
                routing_key: queue_name.clone(),
            }));
            let class_id = method.get_amqp_class_id();
            let deliver_frame = AMQPFrame::Method(channel.id(), method);
            conn.channels.handle_frame(deliver_frame).unwrap();
            let channel_state = channel.status().receiver_state();
            let expected_state = ChannelReceiverState::WillReceiveContent(
                class_id,
                Some(queue_name.clone()),
                Some(consumer_tag.clone()),
            );
            assert_eq!(channel_state, expected_state);
        }
        {
            let header_frame = AMQPFrame::Header(
                channel.id(),
                60,
                Box::new(AMQPContentHeader {
                    class_id: 60,
                    weight: 0,
                    body_size: 2,
                    properties: BasicProperties::default(),
                }),
            );
            conn.channels.handle_frame(header_frame).unwrap();
            let channel_state = channel.status().receiver_state();
            let expected_state = ChannelReceiverState::ReceivingContent(
                Some(queue_name.clone()),
                Some(consumer_tag.clone()),
                2,
            );
            assert_eq!(channel_state, expected_state);
        }
        {
            let body_frame = AMQPFrame::Body(channel.id(), "{}".as_bytes().to_vec());
            conn.channels.handle_frame(body_frame).unwrap();
            let channel_state = channel.status().state();
            let expected_state = ChannelState::Connected;
            assert_eq!(channel_state, expected_state);
        }
    }

    #[test]
    fn basic_consume_empty_payload() {
        let _ = env_logger::try_init();

        use crate::consumer::Consumer;
        use crate::queue::{Queue, QueueState};

        // Bootstrap connection state to a consuming state
        let socket_state = SocketState::default();
        let waker = socket_state.handle();
        let executor = Arc::new(DefaultExecutor::default());
        let internal_rpc = InternalRPC::new(executor.clone(), waker.clone());
        let conn = Connection::new(
            waker,
            internal_rpc.handle(),
            Frames::default(),
            executor.clone(),
        );
        conn.status.set_state(ConnectionState::Connected);
        conn.configuration.set_channel_max(2047);
        let channel = conn.channels.create(conn.closer.clone()).unwrap();
        channel.set_state(ChannelState::Connected);
        let queue_name = ShortString::from("consumed");
        let mut queue: QueueState = Queue::new(queue_name.clone(), 0, 0).into();
        let consumer_tag = ShortString::from("consumer-tag");
        let consumer = Consumer::new(consumer_tag.clone(), executor);
        queue.register_consumer(consumer_tag.clone(), consumer);
        conn.channels
            .with_channel(channel.id(), |c| c.register_queue(queue));
        // Now test the state machine behaviour
        {
            let method = AMQPClass::Basic(basic::AMQPMethod::Deliver(basic::Deliver {
                consumer_tag: consumer_tag.clone(),
                delivery_tag: 1,
                redelivered: false,
                exchange: "".into(),
                routing_key: queue_name.clone(),
            }));
            let class_id = method.get_amqp_class_id();
            let deliver_frame = AMQPFrame::Method(channel.id(), method);
            conn.channels.handle_frame(deliver_frame).unwrap();
            let channel_state = channel.status().receiver_state();
            let expected_state = ChannelReceiverState::WillReceiveContent(
                class_id,
                Some(queue_name.clone()),
                Some(consumer_tag.clone()),
            );
            assert_eq!(channel_state, expected_state);
        }
        {
            let header_frame = AMQPFrame::Header(
                channel.id(),
                60,
                Box::new(AMQPContentHeader {
                    class_id: 60,
                    weight: 0,
                    body_size: 0,
                    properties: BasicProperties::default(),
                }),
            );
            conn.channels.handle_frame(header_frame).unwrap();
            let channel_state = channel.status().state();
            let expected_state = ChannelState::Connected;
            assert_eq!(channel_state, expected_state);
        }
    }
}
<commit_msg>Connection: drop self in run<commit_after>use crate::{
    channel::Channel,
    channels::Channels,
    configuration::Configuration,
    connection_closer::ConnectionCloser,
    connection_properties::ConnectionProperties,
    connection_status::{ConnectionState, ConnectionStatus, ConnectionStep},
    executor::{DefaultExecutor, Executor},
    frames::Frames,
    internal_rpc::{InternalRPC, InternalRPCHandle},
    io_loop::IoLoop,
    reactor::DefaultReactorBuilder,
    socket_state::{SocketState, SocketStateHandle},
    tcp::{AMQPUriTcpExt, HandshakeResult, TLSConfig},
    thread::ThreadHandle,
    types::ShortUInt,
    uri::AMQPUri,
    Error, Promise, PromiseChain, Result,
};
use amq_protocol::frame::{AMQPFrame, ProtocolVersion};
use log::{log_enabled, Level::Trace};
use std::{fmt, io, sync::Arc};

pub struct Connection {
    configuration: Configuration,
    status: ConnectionStatus,
    channels: Channels,
    io_loop: ThreadHandle,
    closer: Arc<ConnectionCloser>,
}

impl Connection {
    fn new(
        waker: SocketStateHandle,
        internal_rpc: InternalRPCHandle,
        frames: Frames,
        executor: Arc<dyn Executor>,
    ) -> Self {
        let configuration = Configuration::default();
        let status = ConnectionStatus::default();
        let channels = Channels::new(
            configuration.clone(),
            status.clone(),
            waker,
            internal_rpc.clone(),
            frames,
            executor,
        );
        let closer = Arc::new(ConnectionCloser::new(status.clone(), internal_rpc));
        let connection = Self {
            configuration,
            status,
            channels,
            io_loop: ThreadHandle::default(),
            closer,
        };

        connection.channels.create_zero();
        connection
    }

    /// Connect to an AMQP Server
    pub fn connect(uri: &str, options: ConnectionProperties) -> PromiseChain<Connection> {
        Connect::connect(uri, options, TLSConfig::default())
    }

    /// Connect to an AMQP Server
    pub fn connect_with_config(
        uri: &str,
        options: ConnectionProperties,
        config: TLSConfig<'_, '_, '_>,
    ) -> PromiseChain<Connection> {
        Connect::connect(uri, options, config)
    }

    /// Connect to an AMQP Server
    pub fn connect_uri(uri: AMQPUri, options: ConnectionProperties) -> PromiseChain<Connection> {
        Connect::connect(uri, options, TLSConfig::default())
    }

    /// Connect to an AMQP Server
    pub fn connect_uri_with_identity(
        uri: AMQPUri,
        options: ConnectionProperties,
        config: TLSConfig<'_, '_, '_>,
    ) -> PromiseChain<Connection> {
        Connect::connect(uri, options, config)
    }

    pub fn create_channel(&self) -> PromiseChain<Channel> {
        if !self.status.connected() {
            return PromiseChain::new_with_data(Err(Error::InvalidConnectionState(
                self.status.state(),
            )));
        }
        match self.channels.create(self.closer.clone()) {
            Ok(channel) => self
                .channels
                .with_channel(channel.id(), |c| c.channel_open(channel))
                .expect("internal error creating channel"),
            Err(error) => PromiseChain::new_with_data(Err(error)),
        }
    }

    /// Block current thread while the connection is still active.
    /// This is useful when you only have a consumer and nothing else keeping your application
    /// "alive".
    pub fn run(self) -> Result<()> {
        let io_loop = self.io_loop.clone();
        drop(self);
        io_loop.wait("io loop")
    }

    pub fn on_error<E: FnMut(Error) + Send + 'static>(&self, handler: E) {
        self.channels.set_error_handler(handler);
    }

    pub fn configuration(&self) -> &Configuration {
        &self.configuration
    }

    pub fn status(&self) -> &ConnectionStatus {
        &self.status
    }

    pub fn close(&self, reply_code: ShortUInt, reply_text: &str) -> Promise<()> {
        self.channels
            .with_channel(0, |channel0| {
                channel0.connection_close(reply_code, reply_text, 0, 0)
            })
            .unwrap_or_else(|| Promise::new_with_data(Ok(())))
    }

    /// Block all consumers and publishers on this connection
    pub fn block(&self, reason: &str) -> Promise<()> {
        self.channels
            .with_channel(0, |channel0| channel0.connection_blocked(reason))
            .unwrap_or_else(|| {
                Promise::new_with_data(Err(Error::InvalidConnectionState(self.status.state())))
            })
    }

    /// Unblock all consumers and publishers on this connection
    pub fn unblock(&self) -> Promise<()> {
        self.channels
            .with_channel(0, |channel0| channel0.connection_unblocked())
            .unwrap_or_else(|| {
                Promise::new_with_data(Err(Error::InvalidConnectionState(self.status.state())))
            })
    }

    /// Update the secret used by some authentication module such as OAuth2
    pub fn update_secret(&self, new_secret: &str, reason: &str) -> Promise<()> {
        self.channels
            .with_channel(0, |channel0| {
                channel0.connection_update_secret(new_secret, reason)
            })
            .unwrap_or_else(|| {
                Promise::new_with_data(Err(Error::InvalidConnectionState(self.status.state())))
            })
    }

    pub fn connector(
        mut options: ConnectionProperties,
    ) -> impl FnOnce(AMQPUri, HandshakeResult) -> PromiseChain<Connection> + 'static {
        move |uri, handshake_result| {
            let executor = options
                .executor
                .take()
                .unwrap_or_else(|| Arc::new(DefaultExecutor::default()));
            let reactor_builder = options
                .reactor_builder
                .take()
                .unwrap_or_else(|| Arc::new(DefaultReactorBuilder));
            let socket_state = SocketState::default();
            let waker = socket_state.handle();
            let internal_rpc = InternalRPC::new(executor.clone(), waker.clone());
            let frames = Frames::default();
            let conn = Connection::new(waker, internal_rpc.handle(), frames.clone(), executor);
            let status = conn.status.clone();
            let configuration = conn.configuration.clone();
            status.set_vhost(&uri.vhost);
            status.set_username(&uri.authority.userinfo.username);
            if let Some(frame_max) = uri.query.frame_max {
                configuration.set_frame_max(frame_max);
            }
            if let Some(channel_max) = uri.query.channel_max {
                configuration.set_channel_max(channel_max);
            }
            if let Some(heartbeat) = uri.query.heartbeat {
                configuration.set_heartbeat(heartbeat);
            }
            let (promise, resolver) = Promise::new();
            if log_enabled!(Trace) {
                promise.set_marker("ProtocolHeader".into());
            }
            let channels = conn.channels.clone();
            channels.with_channel(0, |channel0| {
                channel0.send_frame(
                    AMQPFrame::ProtocolHeader(ProtocolVersion::amqp_0_9_1()),
                    resolver,
                    None,
                )
            });
            let (promise, resolver) = PromiseChain::after(promise);
            if log_enabled!(Trace) {
                promise.set_marker("ProtocolHeader.Ok".into());
            }
            let io_loop_handle = conn.io_loop.clone();
            status.set_state(ConnectionState::Connecting);
            status.set_connection_step(ConnectionStep::ProtocolHeader(
                resolver,
                conn,
                uri.authority.userinfo.into(),
                uri.query.auth_mechanism.unwrap_or_default(),
                options,
            ));
            IoLoop::new(
                status,
                configuration,
                channels,
                internal_rpc,
                frames,
                socket_state,
                io_loop_handle,
                handshake_result,
                &*reactor_builder,
            )
            .and_then(IoLoop::start)
            .map(|()| promise)
            .unwrap_or_else(|err| PromiseChain::new_with_data(Err(err)))
        }
    }
}

impl fmt::Debug for Connection {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Connection")
            .field("configuration", &self.configuration)
            .field("status", &self.status)
            .field("channels", &self.channels)
            .finish()
    }
}

/// Trait providing a method to connect to an AMQP server
pub trait Connect {
    /// connect to an AMQP server
    fn connect(
        self,
        options: ConnectionProperties,
        config: TLSConfig<'_, '_, '_>,
    ) -> PromiseChain<Connection>;
}

impl Connect for AMQPUri {
    fn connect(
        self,
        options: ConnectionProperties,
        config: TLSConfig<'_, '_, '_>,
    ) -> PromiseChain<Connection> {
        let stream = AMQPUriTcpExt::connect_with_config(&self, config);
        Connection::connector(options)(self, stream)
    }
}

impl Connect for &str {
    fn connect(
        self,
        options: ConnectionProperties,
        config: TLSConfig<'_, '_, '_>,
    ) -> PromiseChain<Connection> {
        match self.parse::<AMQPUri>() {
            Ok(uri) => Connect::connect(uri, options, config),
            Err(err) => {
                PromiseChain::new_with_data(Err(io::Error::new(io::ErrorKind::Other, err).into()))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use env_logger;

    use super::*;
    use crate::channel_receiver_state::ChannelReceiverState;
    use crate::channel_status::ChannelState;
    use crate::types::ShortString;
    use crate::BasicProperties;
    use amq_protocol::frame::AMQPContentHeader;
    use amq_protocol::protocol::{basic, AMQPClass};

    #[test]
    fn basic_consume_small_payload() {
        let _ = env_logger::try_init();

        use crate::consumer::Consumer;
        use crate::queue::{Queue, QueueState};

        // Bootstrap connection state to a consuming state
        let executor = Arc::new(DefaultExecutor::default());
        let socket_state = SocketState::default();
        let waker = socket_state.handle();
        let internal_rpc = InternalRPC::new(executor.clone(), waker.clone());
        let conn = Connection::new(
            waker,
            internal_rpc.handle(),
            Frames::default(),
            executor.clone(),
        );
        conn.status.set_state(ConnectionState::Connected);
        conn.configuration.set_channel_max(2047);
        let channel = conn.channels.create(conn.closer.clone()).unwrap();
        channel.set_state(ChannelState::Connected);
        let queue_name = ShortString::from("consumed");
        let mut queue: QueueState = Queue::new(queue_name.clone(), 0, 0).into();
        let consumer_tag = ShortString::from("consumer-tag");
        let consumer = Consumer::new(consumer_tag.clone(), executor);
        queue.register_consumer(consumer_tag.clone(), consumer);
        conn.channels
            .with_channel(channel.id(), |c| c.register_queue(queue));
        // Now test the state machine behaviour
        {
            let method = AMQPClass::Basic(basic::AMQPMethod::Deliver(basic::Deliver {
                consumer_tag: consumer_tag.clone(),
                delivery_tag: 1,
                redelivered: false,
                exchange: "".into(),
                routing_key: queue_name.clone(),
            }));
            let class_id = method.get_amqp_class_id();
            let deliver_frame = AMQPFrame::Method(channel.id(), method);
            conn.channels.handle_frame(deliver_frame).unwrap();
            let channel_state = channel.status().receiver_state();
            let expected_state = ChannelReceiverState::WillReceiveContent(
                class_id,
                Some(queue_name.clone()),
                Some(consumer_tag.clone()),
            );
            assert_eq!(channel_state, expected_state);
        }
        {
            let header_frame = AMQPFrame::Header(
                channel.id(),
                60,
                Box::new(AMQPContentHeader {
                    class_id: 60,
                    weight: 0,
                    body_size: 2,
                    properties: BasicProperties::default(),
                }),
            );
            conn.channels.handle_frame(header_frame).unwrap();
            let channel_state = channel.status().receiver_state();
            let expected_state = ChannelReceiverState::ReceivingContent(
                Some(queue_name.clone()),
                Some(consumer_tag.clone()),
                2,
            );
            assert_eq!(channel_state, expected_state);
        }
        {
            let body_frame = AMQPFrame::Body(channel.id(), "{}".as_bytes().to_vec());
            conn.channels.handle_frame(body_frame).unwrap();
            let channel_state = channel.status().state();
            let expected_state = ChannelState::Connected;
            assert_eq!(channel_state, expected_state);
        }
    }

    #[test]
    fn basic_consume_empty_payload() {
        let _ = env_logger::try_init();

        use crate::consumer::Consumer;
        use crate::queue::{Queue, QueueState};

        // Bootstrap connection state to a consuming state
        let socket_state = SocketState::default();
        let waker = socket_state.handle();
        let executor = Arc::new(DefaultExecutor::default());
        let internal_rpc = InternalRPC::new(executor.clone(), waker.clone());
        let conn = Connection::new(
            waker,
            internal_rpc.handle(),
            Frames::default(),
            executor.clone(),
        );
        conn.status.set_state(ConnectionState::Connected);
        conn.configuration.set_channel_max(2047);
        let channel = conn.channels.create(conn.closer.clone()).unwrap();
        channel.set_state(ChannelState::Connected);
        let queue_name = ShortString::from("consumed");
        let mut queue: QueueState = Queue::new(queue_name.clone(), 0, 0).into();
        let consumer_tag = ShortString::from("consumer-tag");
        let consumer = Consumer::new(consumer_tag.clone(), executor);
        queue.register_consumer(consumer_tag.clone(), consumer);
        conn.channels
            .with_channel(channel.id(), |c| c.register_queue(queue));
        // Now test the state machine behaviour
        {
            let method = AMQPClass::Basic(basic::AMQPMethod::Deliver(basic::Deliver {
                consumer_tag: consumer_tag.clone(),
                delivery_tag: 1,
                redelivered: false,
                exchange: "".into(),
                routing_key: queue_name.clone(),
            }));
            let class_id = method.get_amqp_class_id();
            let deliver_frame = AMQPFrame::Method(channel.id(), method);
            conn.channels.handle_frame(deliver_frame).unwrap();
            let channel_state = channel.status().receiver_state();
            let expected_state = ChannelReceiverState::WillReceiveContent(
                class_id,
                Some(queue_name.clone()),
                Some(consumer_tag.clone()),
            );
            assert_eq!(channel_state, expected_state);
        }
        {
            let header_frame = AMQPFrame::Header(
                channel.id(),
                60,
                Box::new(AMQPContentHeader {
                    class_id: 60,
                    weight: 0,
                    body_size: 0,
                    properties: BasicProperties::default(),
                }),
            );
            conn.channels.handle_frame(header_frame).unwrap();
            let channel_state = channel.status().state();
            let expected_state = ChannelState::Connected;
            assert_eq!(channel_state, expected_state);
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
mod chunk {

    use std::fmt;
    use std::rc::Rc;
    use std::rc::Weak;

    struct Address{
        x: u64,
        y: u64,
        z: u64
    }

    struct Chunk {
        address: Address,
        children: [Option<Rc<Chunk>>; 8],
        entities: Vec<Box<Entity>>,
        parent: Option<Weak<Chunk>>,
        scale: u8,
        summary: i32,
    }

    struct Entity {
        mass: Rc<Chunk>,
        velocity: [f64; 3],
    }

    impl Address {
        fn from_string(address: String) -> Option<Address> {
            let mut xyz: (u64, u64, u64) = (1, 1, 1);
            let mut xyz_add: (u64, u64, u64);

            for (i, c) in address.chars().enumerate() {
                if i > 63 {
                    break;
                }
                xyz_add =  match c.to_digit(8) {
                    Some(0) => (0, 0, 0),
                    Some(1) => (0, 0, 1),
                    Some(2) => (0, 1, 0),
                    Some(3) => (0, 1, 1),
                    Some(4) => (1, 0, 0),
                    Some(5) => (1, 0, 1),
                    Some(6) => (1, 1, 0),
                    Some(7) => (1, 1, 1),
                    _ => return None,
                };
                xyz = (xyz.0 << 1, xyz.1 << 1, xyz.2 << 1);
                xyz = (xyz.0 + xyz_add.0, xyz.1 + xyz_add.1, xyz.2 + xyz_add.2);
            }
            Some(Address {x: xyz.0, y: xyz.1, z: xyz.2})
        }
    }

    impl ToString for Address {
        fn to_string(&self) -> String {
            String::from_str("")
        }
    }

    impl PartialEq for Address {
        fn eq(&self, other: &Self) -> bool {
            (((self.x == other.x) && (self.y == other.y)) && (self.z == other.z))
        }
    }

    impl fmt::Show for Address {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "Address({}, {}, {})", self.x, self.y, self.z)
        }
    }

    impl Chunk {
        fn get_child(self, x: u8, y: u8, z: u8) -> Option<Rc<Chunk>> {
            match (x, y, z) {
                //(0, 0, 0) => self.children[0],
                //(0, 0, 1) => self.children[1],
                (0, 1, 0) => self.children[2],
                //(0, 1, 1) => self.children[3],
                //(1, 0, 0) => self.children[4],
                //(1, 0, 1) => self.children[5],
                //(1, 1, 0) => self.children[6],
                //(1, 1, 1) => self.children[7],
                _ => None,
            }
        }
    }

    #[test]
    fn test_adder_from_string() {
        let known = Option::Some(Address {x: 0b11, y: 0b11, z: 0b11});
        let unknown = Address::from_string(String::from_str("7"));
        assert_eq!(known, unknown)
    }
}
<commit_msg>Remove problem code<commit_after>#![allow(dead_code)]
mod chunk {

    use std::fmt;
    use std::rc::Rc;
    use std::rc::Weak;

    struct Address{
        x: u64,
        y: u64,
        z: u64
    }

    struct Chunk {
        address: Address,
        children: [Option<Rc<Chunk>>; 8],
        entities: Vec<Box<Entity>>,
        parent: Option<Weak<Chunk>>,
        scale: u8,
        summary: i32,
    }

    struct Entity {
        mass: Rc<Chunk>,
        velocity: [f64; 3],
    }

    impl Address {
        fn from_string(address: String) -> Option<Address> {
            let mut xyz: (u64, u64, u64) = (1, 1, 1);
            let mut xyz_add: (u64, u64, u64);

            for (i, c) in address.chars().enumerate() {
                if i > 63 {
                    break;
                }
                xyz_add =  match c.to_digit(8) {
                    Some(0) => (0, 0, 0),
                    Some(1) => (0, 0, 1),
                    Some(2) => (0, 1, 0),
                    Some(3) => (0, 1, 1),
                    Some(4) => (1, 0, 0),
                    Some(5) => (1, 0, 1),
                    Some(6) => (1, 1, 0),
                    Some(7) => (1, 1, 1),
                    _ => return None,
                };
                xyz = (xyz.0 << 1, xyz.1 << 1, xyz.2 << 1);
                xyz = (xyz.0 + xyz_add.0, xyz.1 + xyz_add.1, xyz.2 + xyz_add.2);
            }
            Some(Address {x: xyz.0, y: xyz.1, z: xyz.2})
        }
    }

    impl ToString for Address {
        fn to_string(&self) -> String {
            String::from_str("")
        }
    }

    impl PartialEq for Address {
        fn eq(&self, other: &Self) -> bool {
            (((self.x == other.x) && (self.y == other.y)) && (self.z == other.z))
        }
    }

    impl fmt::Show for Address {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "Address({}, {}, {})", self.x, self.y, self.z)
        }
    }

    impl Chunk {
    }

    #[test]
    fn test_adder_from_string() {
        let known = Option::Some(Address {x: 0b11, y: 0b11, z: 0b11});
        let unknown = Address::from_string(String::from_str("7"));
        assert_eq!(known, unknown)
    }
}
<|endoftext|>