<commit_before>use calx::{RngExt, hex_disc, HexGeom, hex_neighbors};
use euclid::{self, vec2};
use rand::{self, Rng};
use std::collections::HashSet;

pub type Point2D = euclid::Point2D<i32>;
pub type Size2D = euclid::Size2D<i32>;

pub trait Dungeon {
    type Prefab: Prefab;

    /// Return a random prefab room.
    fn sample_prefab<R: Rng>(&mut self, rng: &mut R) -> Self::Prefab;

    /// Add a large open continuous region to dungeon.
    fn dig_chamber<I: IntoIterator<Item = Point2D>>(&mut self, area: I);

    /// Add a narrow corridor to dungeon.
    fn dig_corridor<I: IntoIterator<Item = Point2D>>(&mut self, path: I);

    fn add_prefab(&mut self, prefab: &Self::Prefab, pos: Point2D);

    fn add_door(&mut self, pos: Point2D);

    fn add_up_stairs(&mut self, pos: Point2D);

    fn add_down_stairs(&mut self, pos: Point2D);
}

pub trait Prefab {
    fn contains(&self, pos: Point2D) -> bool;
    fn can_make_door(&self, pos: Point2D) -> bool;
    fn size(&self) -> Size2D;
}

pub struct DigCavesGen {
    domain: Vec<Point2D>,
}

impl DigCavesGen {
    pub fn new<I: IntoIterator<Item = Point2D>>(domain: I) -> DigCavesGen {
        DigCavesGen { domain: domain.into_iter().collect() }
    }

    pub fn dig<R: Rng, D, P>(&self, rng: &mut R, d: &mut D)
    where
        D: Dungeon<Prefab = P>,
        P: Prefab,
    {
        const INIT_P: f32 = 0.65;
        const N_ITERS: usize = 3;
        const WALL_THRESHOLD: u32 = 3;
        const MINIMAL_REGION_SIZE: usize = 8;

        // Initial cellular automata run, produces okay looking but usually not fully connected
        // cave map.
        let mut dug: HashSet<Point2D> = self.domain
            .iter()
            .filter(|_| rng.with_chance(INIT_P))
            .cloned()
            .collect();

        for _ in 0..N_ITERS {
            let mut dug2 = dug.clone();

            for &p in &self.domain {
                let n_walls: u32 = hex_disc(p, 1)
                    .filter(|&p2| p2 != p)
                    .map(|p2| !dug.contains(&p2) as u32)
                    .sum();
                let n_walls_2: u32 = hex_disc(p, 2)
                    .filter(|&p2| p2 != p)
                    .map(|p2| !dug.contains(&p2) as u32)
                    .sum();

                // Add a wall if there are either neighboring walls or if the cell is in the
                // centes of a large empty region.
                if n_walls >= WALL_THRESHOLD || n_walls_2 == 0 {
                    dug2.remove(&p);
                } else {
                    dug2.insert(p);
                }
            }

            dug = dug2;
        }

        // Connect separate regions
        let mut regions = separate_regions(dug.clone());
        // Remove uselessly small regions
        regions.retain(|a| a.len() >= MINIMAL_REGION_SIZE);
        // Sort unconnected regions from largest to smallest
        regions.sort_unstable_by(|a, b| b.len().cmp(&a.len()));

        dug = regions.pop().unwrap().into_iter().collect();

        while let Some(next_region) = regions.pop() {
            // Add each secondary region to the dug set, carving a tunnel from dug to its random
            // point.
            // XXX: Might be neater to try to minimize the length of the tunnel to carve
            let p1: Point2D = *rand::sample(rng, dug.iter(), 1)[0];
            let p2: Point2D = *rand::sample(rng, next_region.iter(), 1)[0];

            dug.extend(next_region.into_iter());
            dug.extend(jaggly_line(rng, p1, p2).into_iter());
        }

        debug_assert!(!dug.is_empty());
        debug_assert!(is_connected(dug.clone()));

        d.dig_chamber(dug.clone());

        // Pick stair sites
        let upstair_sites: Vec<Point2D> = self.domain
            .iter()
            .filter(|&&p| is_upstair_pos(&dug, p))
            .cloned()
            .collect();
        let downstair_sites: Vec<Point2D> = self.domain
            .iter()
            .filter(|&&p| is_downstair_pos(&dug, p))
            .cloned()
            .collect();
        d.add_up_stairs(rand::sample(rng, upstair_sites.into_iter(), 1)[0]);
        d.add_down_stairs(rand::sample(rng, downstair_sites.into_iter(), 1)[0]);

        fn is_upstair_pos(dug: &HashSet<Point2D>, pos: Point2D) -> bool {
            // XXX: Enclosure descriptions, still awful to write...
            dug.contains(&(pos + vec2(1, 1))) && !dug.contains(&(pos + vec2(1, 0))) &&
                !dug.contains(&(pos + vec2(0, 1))) &&
                !dug.contains(&(pos + vec2(-1, -1))) &&
                !dug.contains(&(pos + vec2(-1, 0))) &&
                !dug.contains(&(pos + vec2(0, -1)))
        }

        fn is_downstair_pos(dug: &HashSet<Point2D>, pos: Point2D) -> bool {
            // Downstairs needs an extra enclosure behind it for a tile graphics hack.
            dug.contains(&(pos + vec2(-1, -1))) && !dug.contains(&(pos + vec2(-1, 0))) &&
                !dug.contains(&(pos + vec2(0, -1))) &&
                !dug.contains(&(pos + vec2(1, 1))) &&
                !dug.contains(&(pos + vec2(1, 0))) &&
                !dug.contains(&(pos + vec2(0, 1))) &&
                !dug.contains(&(pos + vec2(2, 2))) &&
                !dug.contains(&(pos + vec2(2, 1))) && !dug.contains(&(pos + vec2(1, 2)))
        }
    }
}

fn separate_regions(mut points: HashSet<Point2D>) -> Vec<HashSet<Point2D>> {
    let mut ret = Vec::new();

    while !points.is_empty() {
        let seed = *points.iter().next().unwrap();
        let subset = flood_fill(points.clone(), seed);
        debug_assert!(!subset.is_empty());
        points = points.difference(&subset).cloned().collect();
        ret.push(subset);
    }

    ret
}

fn flood_fill(mut points: HashSet<Point2D>, seed: Point2D) -> HashSet<Point2D> {
    let mut ret = HashSet::new();
    let mut edge = HashSet::new();

    if !points.remove(&seed) {
        return ret;
    }
    edge.insert(seed);

    while !edge.is_empty() {
        // XXX: Is there a set data type that supports 'pop'?
        let pos = *edge.iter().next().unwrap();
        edge.remove(&pos);
        ret.insert(pos);

        for p in hex_neighbors(pos) {
            if points.contains(&p) {
                debug_assert!(!ret.contains(&p) && !edge.contains(&p));
                points.remove(&p);
                edge.insert(p);
            }
        }
    }

    ret
}

fn is_connected(points: HashSet<Point2D>) -> bool { separate_regions(points).len() <= 1 }

// TODO return impl
fn jaggly_line<R: Rng>(rng: &mut R, p1: Point2D, p2: Point2D) -> Vec<Point2D> {
    let mut ret = Vec::new();
    let mut p = p1;
    ret.push(p);

    while p != p2 {
        let dist = (p2 - p).hex_dist();
        let options = hex_neighbors(p).filter(|&q| (p2 - q).hex_dist() < dist);
        p = rand::sample(rng, options, 1)[0];
        ret.push(p);
    }

    ret
}
<commit_msg>Determinize mapgen<commit_after>use calx::{RngExt, hex_disc, HexGeom, hex_neighbors};
use euclid::{self, vec2};
use rand::{self, Rng};
use std::collections::HashSet;
use std::cmp::Ordering;

pub type Point2D = euclid::Point2D<i32>;
pub type Size2D = euclid::Size2D<i32>;

pub trait Dungeon {
    type Prefab: Prefab;

    /// Return a random prefab room.
    fn sample_prefab<R: Rng>(&mut self, rng: &mut R) -> Self::Prefab;

    /// Add a large open continuous region to dungeon.
    fn dig_chamber<I: IntoIterator<Item = Point2D>>(&mut self, area: I);

    /// Add a narrow corridor to dungeon.
    fn dig_corridor<I: IntoIterator<Item = Point2D>>(&mut self, path: I);

    fn add_prefab(&mut self, prefab: &Self::Prefab, pos: Point2D);

    fn add_door(&mut self, pos: Point2D);

    fn add_up_stairs(&mut self, pos: Point2D);

    fn add_down_stairs(&mut self, pos: Point2D);
}

pub trait Prefab {
    fn contains(&self, pos: Point2D) -> bool;
    fn can_make_door(&self, pos: Point2D) -> bool;
    fn size(&self) -> Size2D;
}

pub struct DigCavesGen {
    domain: Vec<Point2D>,
}

impl DigCavesGen {
    pub fn new<I: IntoIterator<Item = Point2D>>(domain: I) -> DigCavesGen {
        DigCavesGen { domain: domain.into_iter().collect() }
    }

    pub fn dig<R: Rng, D, P>(&self, rng: &mut R, d: &mut D)
    where
        D: Dungeon<Prefab = P>,
        P: Prefab,
    {
        const INIT_P: f32 = 0.65;
        const N_ITERS: usize = 3;
        const WALL_THRESHOLD: u32 = 3;
        const MINIMAL_REGION_SIZE: usize = 8;

        // Initial cellular automata run, produces okay looking but usually not fully connected
        // cave map.
        let mut dug: HashSet<Point2D> = self.domain
            .iter()
            .filter(|_| rng.with_chance(INIT_P))
            .cloned()
            .collect();

        for _ in 0..N_ITERS {
            let mut dug2 = dug.clone();

            for &p in &self.domain {
                let n_walls: u32 = hex_disc(p, 1)
                    .filter(|&p2| p2 != p)
                    .map(|p2| !dug.contains(&p2) as u32)
                    .sum();
                let n_walls_2: u32 = hex_disc(p, 2)
                    .filter(|&p2| p2 != p)
                    .map(|p2| !dug.contains(&p2) as u32)
                    .sum();

                // Add a wall if there are either neighboring walls or if the cell is in the
                // centes of a large empty region.
                if n_walls >= WALL_THRESHOLD || n_walls_2 == 0 {
                    dug2.remove(&p);
                } else {
                    dug2.insert(p);
                }
            }

            dug = dug2;
        }

        // Connect separate regions
        let mut regions = separate_regions(dug.clone());
        // Remove uselessly small regions
        regions.retain(|a| a.len() >= MINIMAL_REGION_SIZE);
        // Sort unconnected regions from largest to smallest
        regions.sort_unstable_by(|a, b| b.len().cmp(&a.len()));

        dug = regions.pop().unwrap().into_iter().collect();

        while let Some(next_region) = regions.pop() {
            // FIXME: Get sorted container for points
            let sorted_dug = sorted(&dug);
            let sorted_region = sorted(&next_region);

            // Add each secondary region to the dug set, carving a tunnel from dug to its random
            // point.
            // XXX: Might be neater to try to minimize the length of the tunnel to carve
            let p1: Point2D = rand::sample(rng, sorted_dug.into_iter(), 1)[0];
            let p2: Point2D = rand::sample(rng, sorted_region.into_iter(), 1)[0];

            dug.extend(next_region.into_iter());
            dug.extend(jaggly_line(rng, p1, p2).into_iter());
        }

        debug_assert!(!dug.is_empty());
        debug_assert!(is_connected(dug.clone()));

        d.dig_chamber(dug.clone());

        // Pick stair sites
        let mut upstair_sites: Vec<Point2D> = self.domain
            .iter()
            .filter(|&&p| is_upstair_pos(&dug, p))
            .cloned()
            .collect();
        upstair_sites.sort_by(pt_ord);

        let mut downstair_sites: Vec<Point2D> = self.domain
            .iter()
            .filter(|&&p| is_downstair_pos(&dug, p))
            .cloned()
            .collect();
        downstair_sites.sort_by(pt_ord);

        d.add_up_stairs(rand::sample(rng, upstair_sites.into_iter(), 1)[0]);
        d.add_down_stairs(rand::sample(rng, downstair_sites.into_iter(), 1)[0]);

        fn is_upstair_pos(dug: &HashSet<Point2D>, pos: Point2D) -> bool {
            // XXX: Enclosure descriptions, still awful to write...
            dug.contains(&(pos + vec2(1, 1))) && !dug.contains(&(pos + vec2(1, 0))) &&
                !dug.contains(&(pos + vec2(0, 1))) &&
                !dug.contains(&(pos + vec2(-1, -1))) &&
                !dug.contains(&(pos + vec2(-1, 0))) &&
                !dug.contains(&(pos + vec2(0, -1)))
        }

        fn is_downstair_pos(dug: &HashSet<Point2D>, pos: Point2D) -> bool {
            // Downstairs needs an extra enclosure behind it for a tile graphics hack.
            dug.contains(&(pos + vec2(-1, -1))) && !dug.contains(&(pos + vec2(-1, 0))) &&
                !dug.contains(&(pos + vec2(0, -1))) &&
                !dug.contains(&(pos + vec2(1, 1))) &&
                !dug.contains(&(pos + vec2(1, 0))) &&
                !dug.contains(&(pos + vec2(0, 1))) &&
                !dug.contains(&(pos + vec2(2, 2))) &&
                !dug.contains(&(pos + vec2(2, 1))) && !dug.contains(&(pos + vec2(1, 2)))
        }
    }
}

fn separate_regions(mut points: HashSet<Point2D>) -> Vec<HashSet<Point2D>> {
    let mut ret = Vec::new();

    while !points.is_empty() {
        let seed = *points.iter().min_by(|a, b| (a.x, a.y).cmp(&(b.x, b.y))).unwrap();
        let subset = flood_fill(points.clone(), seed);
        debug_assert!(!subset.is_empty());
        points = points.difference(&subset).cloned().collect();
        ret.push(subset);
    }

    ret
}

fn flood_fill(mut points: HashSet<Point2D>, seed: Point2D) -> HashSet<Point2D> {
    let mut ret = HashSet::new();
    let mut edge = HashSet::new();

    if !points.remove(&seed) {
        return ret;
    }
    edge.insert(seed);

    while !edge.is_empty() {
        // XXX: Is there a set data type that supports 'pop'?
        let pos = *edge.iter().next().unwrap();
        edge.remove(&pos);
        ret.insert(pos);

        for p in hex_neighbors(pos) {
            if points.contains(&p) {
                debug_assert!(!ret.contains(&p) && !edge.contains(&p));
                points.remove(&p);
                edge.insert(p);
            }
        }
    }

    ret
}

fn is_connected(points: HashSet<Point2D>) -> bool { separate_regions(points).len() <= 1 }

// TODO return impl
fn jaggly_line<R: Rng>(rng: &mut R, p1: Point2D, p2: Point2D) -> Vec<Point2D> {
    let mut ret = Vec::new();
    let mut p = p1;
    ret.push(p);

    while p != p2 {
        let dist = (p2 - p).hex_dist();
        let options = hex_neighbors(p).filter(|&q| (p2 - q).hex_dist() < dist);
        p = rand::sample(rng, options, 1)[0];
        ret.push(p);
    }

    ret
}

// FIXME: Get Points in a fixed-order container to maintain determinism. Failing that, here's a
// helper function for turning a set into an ordered list.
fn sorted(set: &HashSet<Point2D>) -> Vec<Point2D> {
    let mut ret: Vec<Point2D> = set.iter().cloned().collect();
    ret.sort_by(pt_ord);
    ret
}

fn pt_ord(a: &Point2D, b: &Point2D) -> Ordering {
    (a.x, a.y).cmp(&(b.x, b.y))
}
<|endoftext|>


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

use std::convert::From;
use std::fs::File;
use std::io;
use std::net::{IpAddr, SocketAddr};
use std::sync::mpsc;
use std::sync::Arc;
use util::RwLock;

use chrono::prelude::*;

use core::core::hash::Hash;
use core::pow::Difficulty;
use core::{core, ser};
use grin_store;

/// Maximum number of block headers a peer should ever send
pub const MAX_BLOCK_HEADERS: u32 = 512;

/// Maximum number of block bodies a peer should ever ask for and send
#[allow(dead_code)]
pub const MAX_BLOCK_BODIES: u32 = 16;

/// Maximum number of peer addresses a peer should ever send
pub const MAX_PEER_ADDRS: u32 = 256;

/// Maximum number of block header hashes to send as part of a locator
pub const MAX_LOCATORS: u32 = 20;

/// How long a banned peer should be banned for
const BAN_WINDOW: i64 = 10800;

/// The max peer count
const PEER_MAX_COUNT: u32 = 25;

/// min preferred peer count
const PEER_MIN_PREFERRED_COUNT: u32 = 8;

#[derive(Debug)]
pub enum Error {
	Serialization(ser::Error),
	Connection(io::Error),
	/// Header type does not match the expected message type
	BadMessage,
	Banned,
	ConnectionClose,
	Timeout,
	Store(grin_store::Error),
	PeerWithSelf,
	NoDandelionRelay,
	ProtocolMismatch {
		us: u32,
		peer: u32,
	},
	GenesisMismatch {
		us: Hash,
		peer: Hash,
	},
	Send(String),
	PeerException,
}

impl From<ser::Error> for Error {
	fn from(e: ser::Error) -> Error {
		Error::Serialization(e)
	}
}
impl From<grin_store::Error> for Error {
	fn from(e: grin_store::Error) -> Error {
		Error::Store(e)
	}
}
impl From<io::Error> for Error {
	fn from(e: io::Error) -> Error {
		Error::Connection(e)
	}
}
impl<T> From<mpsc::TrySendError<T>> for Error {
	fn from(e: mpsc::TrySendError<T>) -> Error {
		Error::Send(e.to_string())
	}
}

/// Configuration for the peer-to-peer server.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct P2PConfig {
	pub host: IpAddr,
	pub port: u16,

	/// Method used to get the list of seed nodes for initial bootstrap.
	#[serde(default)]
	pub seeding_type: Seeding,

	/// The list of seed nodes, if using Seeding as a seed type
	pub seeds: Option<Vec<String>>,

	/// Capabilities expose by this node, also conditions which other peers this
	/// node will have an affinity toward when connection.
	pub capabilities: Capabilities,

	pub peers_allow: Option<Vec<String>>,

	pub peers_deny: Option<Vec<String>>,

	/// The list of preferred peers that we will try to connect to
	pub peers_preferred: Option<Vec<String>>,

	pub ban_window: Option<i64>,

	pub peer_max_count: Option<u32>,

	pub peer_min_preferred_count: Option<u32>,
}

/// Default address for peer-to-peer connections.
impl Default for P2PConfig {
	fn default() -> P2PConfig {
		let ipaddr = "0.0.0.0".parse().unwrap();
		P2PConfig {
			host: ipaddr,
			port: 13414,
			capabilities: Capabilities::FULL_NODE,
			seeding_type: Seeding::default(),
			seeds: None,
			peers_allow: None,
			peers_deny: None,
			peers_preferred: None,
			ban_window: None,
			peer_max_count: None,
			peer_min_preferred_count: None,
		}
	}
}

/// Note certain fields are options just so they don't have to be
/// included in grin-server.toml, but we don't want them to ever return none
impl P2PConfig {
	/// return ban window
	pub fn ban_window(&self) -> i64 {
		match self.ban_window {
			Some(n) => n,
			None => BAN_WINDOW,
		}
	}

	/// return peer_max_count
	pub fn peer_max_count(&self) -> u32 {
		match self.peer_max_count {
			Some(n) => n,
			None => PEER_MAX_COUNT,
		}
	}

	/// return peer_preferred_count
	pub fn peer_min_preferred_count(&self) -> u32 {
		match self.peer_min_preferred_count {
			Some(n) => n,
			None => PEER_MIN_PREFERRED_COUNT,
		}
	}
}

/// Type of seeding the server will use to find other peers on the network.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum Seeding {
	/// No seeding, mostly for tests that programmatically connect
	None,
	/// A list of seed addresses provided to the server
	List,
	/// Automatically get a list of seeds from multiple DNS
	DNSSeed,
	/// Mostly for tests, where connections are initiated programmatically
	Programmatic,
}

impl Default for Seeding {
	fn default() -> Seeding {
		Seeding::DNSSeed
	}
}

bitflags! {
	/// Options for what type of interaction a peer supports
	#[derive(Serialize, Deserialize)]
	pub struct Capabilities: u32 {
		/// We don't know (yet) what the peer can do.
		const UNKNOWN = 0b00000000;
		/// Can provide full history of headers back to genesis
		/// (for at least one arbitrary fork).
		const HEADER_HIST = 0b00000001;
		/// Can provide block headers and the TxHashSet for some recent-enough
		/// height.
		const TXHASHSET_HIST = 0b00000010;
		/// Can provide a list of healthy peers
		const PEER_LIST = 0b00000100;
		/// Can broadcast and request txs by kernel hash.
		const TX_KERNEL_HASH = 0b00001000;

		/// All nodes right now are "full nodes".
		/// Some nodes internally may maintain longer block histories (archival_mode)
		/// but we do not advertise this to other nodes.
		const FULL_NODE = Capabilities::HEADER_HIST.bits
			| Capabilities::TXHASHSET_HIST.bits
			| Capabilities::PEER_LIST.bits
			| Capabilities::TX_KERNEL_HASH.bits;
	}
}

/// Types of connection
enum_from_primitive! {
	#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
	pub enum Direction {
		Inbound = 0,
		Outbound = 1,
	}
}

/// Ban reason
enum_from_primitive! {
	#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
	pub enum ReasonForBan {
		None = 0,
		BadBlock = 1,
		BadCompactBlock = 2,
		BadBlockHeader = 3,
		BadTxHashSet = 4,
		ManualBan = 5,
	}
}

#[derive(Clone, Debug)]
pub struct PeerLiveInfo {
	pub total_difficulty: Difficulty,
	pub height: u64,
	pub last_seen: DateTime<Utc>,
	pub stuck_detector: DateTime<Utc>,
}

/// General information about a connected peer that's useful to other modules.
#[derive(Clone, Debug)]
pub struct PeerInfo {
	pub capabilities: Capabilities,
	pub user_agent: String,
	pub version: u32,
	pub addr: SocketAddr,
	pub direction: Direction,
	pub live_info: Arc<RwLock<PeerLiveInfo>>,
}

impl PeerInfo {
	/// The current total_difficulty of the peer.
	pub fn total_difficulty(&self) -> Difficulty {
		self.live_info.read().total_difficulty
	}

	/// The current height of the peer.
	pub fn height(&self) -> u64 {
		self.live_info.read().height
	}

	/// Time of last_seen for this peer (via ping/pong).
	pub fn last_seen(&self) -> DateTime<Utc> {
		self.live_info.read().last_seen
	}

	/// Update the total_difficulty, height and last_seen of the peer.
	/// Takes a write lock on the live_info.
	pub fn update(&self, height: u64, total_difficulty: Difficulty) {
		let mut live_info = self.live_info.write();
		if total_difficulty != live_info.total_difficulty {
			live_info.stuck_detector = Utc::now();
		}
		live_info.height = height;
		live_info.total_difficulty = total_difficulty;
		live_info.last_seen = Utc::now()
	}
}

/// Flatten out a PeerInfo and nested PeerLiveInfo (taking a read lock on it)
/// so we can serialize/deserialize the data for the API and the TUI.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PeerInfoDisplay {
	pub capabilities: Capabilities,
	pub user_agent: String,
	pub version: u32,
	pub addr: SocketAddr,
	pub direction: Direction,
	pub total_difficulty: Difficulty,
	pub height: u64,
}

impl From<PeerInfo> for PeerInfoDisplay {
	fn from(info: PeerInfo) -> PeerInfoDisplay {
		PeerInfoDisplay {
			capabilities: info.capabilities.clone(),
			user_agent: info.user_agent.clone(),
			version: info.version.clone(),
			addr: info.addr.clone(),
			direction: info.direction.clone(),
			total_difficulty: info.total_difficulty(),
			height: info.height(),
		}
	}
}

/// The full txhashset data along with indexes required for a consumer to
/// rewind to a consistent requested state.
pub struct TxHashSetRead {
	/// Output tree index the receiver should rewind to
	pub output_index: u64,
	/// Kernel tree index the receiver should rewind to
	pub kernel_index: u64,
	/// Binary stream for the txhashset zipped data
	pub reader: File,
}

/// Bridge between the networking layer and the rest of the system. Handles the
/// forwarding or querying of blocks and transactions from the network among
/// other things.
pub trait ChainAdapter: Sync + Send {
	/// Current total difficulty on our chain
	fn total_difficulty(&self) -> Difficulty;

	/// Current total height
	fn total_height(&self) -> u64;

	/// A valid transaction has been received from one of our peers
	fn transaction_received(&self, tx: core::Transaction, stem: bool);

	fn get_transaction(&self, kernel_hash: Hash) -> Option<core::Transaction>;

	fn tx_kernel_received(&self, kernel_hash: Hash, addr: SocketAddr);

	/// A block has been received from one of our peers. Returns true if the
	/// block could be handled properly and is not deemed defective by the
	/// chain. Returning false means the block will never be valid and
	/// may result in the peer being banned.
	fn block_received(&self, b: core::Block, addr: SocketAddr) -> bool;

	fn compact_block_received(&self, cb: core::CompactBlock, addr: SocketAddr) -> bool;

	fn header_received(&self, bh: core::BlockHeader, addr: SocketAddr) -> bool;

	/// A set of block header has been received, typically in response to a
	/// block
	/// header request.
	fn headers_received(&self, bh: Vec<core::BlockHeader>, addr: SocketAddr) -> bool;

	/// Finds a list of block headers based on the provided locator. Tries to
	/// identify the common chain and gets the headers that follow it
	/// immediately.
	fn locate_headers(&self, locator: Vec<Hash>) -> Vec<core::BlockHeader>;

	/// Gets a full block by its hash.
	fn get_block(&self, h: Hash) -> Option<core::Block>;

	/// Provides a reading view into the current txhashset state as well as
	/// the required indexes for a consumer to rewind to a consistant state
	/// at the provided block hash.
	fn txhashset_read(&self, h: Hash) -> Option<TxHashSetRead>;

	/// Whether the node is ready to accept a new txhashset. If this isn't the
	/// case, the archive is provided without being requested and likely an
	/// attack attempt. This should be checked *before* downloading the whole
	/// state data.
	fn txhashset_receive_ready(&self) -> bool;

	/// Update txhashset downloading progress
	fn txhashset_download_update(
		&self,
		start_time: DateTime<Utc>,
		downloaded_size: u64,
		total_size: u64,
	) -> bool;

	/// Writes a reading view on a txhashset state that's been provided to us.
	/// If we're willing to accept that new state, the data stream will be
	/// read as a zip file, unzipped and the resulting state files should be
	/// rewound to the provided indexes.
	fn txhashset_write(&self, h: Hash, txhashset_data: File, peer_addr: SocketAddr) -> bool;
}

/// Additional methods required by the protocol that don't need to be
/// externally implemented.
pub trait NetAdapter: ChainAdapter {
	/// Find good peers we know with the provided capability and return their
	/// addresses.
	fn find_peer_addrs(&self, capab: Capabilities) -> Vec<SocketAddr>;

	/// A list of peers has been received from one of our peers.
	fn peer_addrs_received(&self, Vec<SocketAddr>);

	/// Heard total_difficulty from a connected peer (via ping/pong).
	fn peer_difficulty(&self, SocketAddr, Difficulty, u64);

	/// Is this peer currently banned?
	fn is_banned(&self, addr: SocketAddr) -> bool;
}
<commit_msg>Fix capabilities (#1944)<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::convert::From;
use std::fs::File;
use std::io;
use std::net::{IpAddr, SocketAddr};
use std::sync::mpsc;
use std::sync::Arc;
use util::RwLock;

use chrono::prelude::*;

use core::core::hash::Hash;
use core::pow::Difficulty;
use core::{core, ser};
use grin_store;

/// Maximum number of block headers a peer should ever send
pub const MAX_BLOCK_HEADERS: u32 = 512;

/// Maximum number of block bodies a peer should ever ask for and send
#[allow(dead_code)]
pub const MAX_BLOCK_BODIES: u32 = 16;

/// Maximum number of peer addresses a peer should ever send
pub const MAX_PEER_ADDRS: u32 = 256;

/// Maximum number of block header hashes to send as part of a locator
pub const MAX_LOCATORS: u32 = 20;

/// How long a banned peer should be banned for
const BAN_WINDOW: i64 = 10800;

/// The max peer count
const PEER_MAX_COUNT: u32 = 25;

/// min preferred peer count
const PEER_MIN_PREFERRED_COUNT: u32 = 8;

#[derive(Debug)]
pub enum Error {
	Serialization(ser::Error),
	Connection(io::Error),
	/// Header type does not match the expected message type
	BadMessage,
	Banned,
	ConnectionClose,
	Timeout,
	Store(grin_store::Error),
	PeerWithSelf,
	NoDandelionRelay,
	ProtocolMismatch {
		us: u32,
		peer: u32,
	},
	GenesisMismatch {
		us: Hash,
		peer: Hash,
	},
	Send(String),
	PeerException,
}

impl From<ser::Error> for Error {
	fn from(e: ser::Error) -> Error {
		Error::Serialization(e)
	}
}
impl From<grin_store::Error> for Error {
	fn from(e: grin_store::Error) -> Error {
		Error::Store(e)
	}
}
impl From<io::Error> for Error {
	fn from(e: io::Error) -> Error {
		Error::Connection(e)
	}
}
impl<T> From<mpsc::TrySendError<T>> for Error {
	fn from(e: mpsc::TrySendError<T>) -> Error {
		Error::Send(e.to_string())
	}
}

/// Configuration for the peer-to-peer server.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct P2PConfig {
	pub host: IpAddr,
	pub port: u16,

	/// Method used to get the list of seed nodes for initial bootstrap.
	#[serde(default)]
	pub seeding_type: Seeding,

	/// The list of seed nodes, if using Seeding as a seed type
	pub seeds: Option<Vec<String>>,

	/// Capabilities expose by this node, also conditions which other peers this
	/// node will have an affinity toward when connection.
	pub capabilities: Capabilities,

	pub peers_allow: Option<Vec<String>>,

	pub peers_deny: Option<Vec<String>>,

	/// The list of preferred peers that we will try to connect to
	pub peers_preferred: Option<Vec<String>>,

	pub ban_window: Option<i64>,

	pub peer_max_count: Option<u32>,

	pub peer_min_preferred_count: Option<u32>,
}

/// Default address for peer-to-peer connections.
impl Default for P2PConfig {
	fn default() -> P2PConfig {
		let ipaddr = "0.0.0.0".parse().unwrap();
		P2PConfig {
			host: ipaddr,
			port: 13414,
			capabilities: Capabilities::HEADER_HIST
				| Capabilities::TXHASHSET_HIST
				| Capabilities::PEER_LIST,
			seeding_type: Seeding::default(),
			seeds: None,
			peers_allow: None,
			peers_deny: None,
			peers_preferred: None,
			ban_window: None,
			peer_max_count: None,
			peer_min_preferred_count: None,
		}
	}
}

/// Note certain fields are options just so they don't have to be
/// included in grin-server.toml, but we don't want them to ever return none
impl P2PConfig {
	/// return ban window
	pub fn ban_window(&self) -> i64 {
		match self.ban_window {
			Some(n) => n,
			None => BAN_WINDOW,
		}
	}

	/// return peer_max_count
	pub fn peer_max_count(&self) -> u32 {
		match self.peer_max_count {
			Some(n) => n,
			None => PEER_MAX_COUNT,
		}
	}

	/// return peer_preferred_count
	pub fn peer_min_preferred_count(&self) -> u32 {
		match self.peer_min_preferred_count {
			Some(n) => n,
			None => PEER_MIN_PREFERRED_COUNT,
		}
	}
}

/// Type of seeding the server will use to find other peers on the network.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum Seeding {
	/// No seeding, mostly for tests that programmatically connect
	None,
	/// A list of seed addresses provided to the server
	List,
	/// Automatically get a list of seeds from multiple DNS
	DNSSeed,
	/// Mostly for tests, where connections are initiated programmatically
	Programmatic,
}

impl Default for Seeding {
	fn default() -> Seeding {
		Seeding::DNSSeed
	}
}

bitflags! {
	/// Options for what type of interaction a peer supports
	#[derive(Serialize, Deserialize)]
	pub struct Capabilities: u32 {
		/// We don't know (yet) what the peer can do.
		const UNKNOWN = 0b00000000;
		/// Can provide full history of headers back to genesis
		/// (for at least one arbitrary fork).
		const HEADER_HIST = 0b00000001;
		/// Can provide block headers and the TxHashSet for some recent-enough
		/// height.
		const TXHASHSET_HIST = 0b00000010;
		/// Can provide a list of healthy peers
		const PEER_LIST = 0b00000100;
		/// Can broadcast and request txs by kernel hash.
		const TX_KERNEL_HASH = 0b00001000;

		/// All nodes right now are "full nodes".
		/// Some nodes internally may maintain longer block histories (archival_mode)
		/// but we do not advertise this to other nodes.
		const FULL_NODE = Capabilities::HEADER_HIST.bits
			| Capabilities::TXHASHSET_HIST.bits
			| Capabilities::PEER_LIST.bits
			| Capabilities::TX_KERNEL_HASH.bits;
	}
}

/// Types of connection
enum_from_primitive! {
	#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
	pub enum Direction {
		Inbound = 0,
		Outbound = 1,
	}
}

/// Ban reason
enum_from_primitive! {
	#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
	pub enum ReasonForBan {
		None = 0,
		BadBlock = 1,
		BadCompactBlock = 2,
		BadBlockHeader = 3,
		BadTxHashSet = 4,
		ManualBan = 5,
	}
}

#[derive(Clone, Debug)]
pub struct PeerLiveInfo {
	pub total_difficulty: Difficulty,
	pub height: u64,
	pub last_seen: DateTime<Utc>,
	pub stuck_detector: DateTime<Utc>,
}

/// General information about a connected peer that's useful to other modules.
#[derive(Clone, Debug)]
pub struct PeerInfo {
	pub capabilities: Capabilities,
	pub user_agent: String,
	pub version: u32,
	pub addr: SocketAddr,
	pub direction: Direction,
	pub live_info: Arc<RwLock<PeerLiveInfo>>,
}

impl PeerInfo {
	/// The current total_difficulty of the peer.
	pub fn total_difficulty(&self) -> Difficulty {
		self.live_info.read().total_difficulty
	}

	/// The current height of the peer.
	pub fn height(&self) -> u64 {
		self.live_info.read().height
	}

	/// Time of last_seen for this peer (via ping/pong).
	pub fn last_seen(&self) -> DateTime<Utc> {
		self.live_info.read().last_seen
	}

	/// Update the total_difficulty, height and last_seen of the peer.
	/// Takes a write lock on the live_info.
	pub fn update(&self, height: u64, total_difficulty: Difficulty) {
		let mut live_info = self.live_info.write();
		if total_difficulty != live_info.total_difficulty {
			live_info.stuck_detector = Utc::now();
		}
		live_info.height = height;
		live_info.total_difficulty = total_difficulty;
		live_info.last_seen = Utc::now()
	}
}

/// Flatten out a PeerInfo and nested PeerLiveInfo (taking a read lock on it)
/// so we can serialize/deserialize the data for the API and the TUI.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PeerInfoDisplay {
	pub capabilities: Capabilities,
	pub user_agent: String,
	pub version: u32,
	pub addr: SocketAddr,
	pub direction: Direction,
	pub total_difficulty: Difficulty,
	pub height: u64,
}

impl From<PeerInfo> for PeerInfoDisplay {
	fn from(info: PeerInfo) -> PeerInfoDisplay {
		PeerInfoDisplay {
			capabilities: info.capabilities.clone(),
			user_agent: info.user_agent.clone(),
			version: info.version.clone(),
			addr: info.addr.clone(),
			direction: info.direction.clone(),
			total_difficulty: info.total_difficulty(),
			height: info.height(),
		}
	}
}

/// The full txhashset data along with indexes required for a consumer to
/// rewind to a consistent requested state.
pub struct TxHashSetRead {
	/// Output tree index the receiver should rewind to
	pub output_index: u64,
	/// Kernel tree index the receiver should rewind to
	pub kernel_index: u64,
	/// Binary stream for the txhashset zipped data
	pub reader: File,
}

/// Bridge between the networking layer and the rest of the system. Handles the
/// forwarding or querying of blocks and transactions from the network among
/// other things.
pub trait ChainAdapter: Sync + Send {
	/// Current total difficulty on our chain
	fn total_difficulty(&self) -> Difficulty;

	/// Current total height
	fn total_height(&self) -> u64;

	/// A valid transaction has been received from one of our peers
	fn transaction_received(&self, tx: core::Transaction, stem: bool);

	fn get_transaction(&self, kernel_hash: Hash) -> Option<core::Transaction>;

	fn tx_kernel_received(&self, kernel_hash: Hash, addr: SocketAddr);

	/// A block has been received from one of our peers. Returns true if the
	/// block could be handled properly and is not deemed defective by the
	/// chain. Returning false means the block will never be valid and
	/// may result in the peer being banned.
	fn block_received(&self, b: core::Block, addr: SocketAddr) -> bool;

	fn compact_block_received(&self, cb: core::CompactBlock, addr: SocketAddr) -> bool;

	fn header_received(&self, bh: core::BlockHeader, addr: SocketAddr) -> bool;

	/// A set of block header has been received, typically in response to a
	/// block
	/// header request.
	fn headers_received(&self, bh: Vec<core::BlockHeader>, addr: SocketAddr) -> bool;

	/// Finds a list of block headers based on the provided locator. Tries to
	/// identify the common chain and gets the headers that follow it
	/// immediately.
	fn locate_headers(&self, locator: Vec<Hash>) -> Vec<core::BlockHeader>;

	/// Gets a full block by its hash.
	fn get_block(&self, h: Hash) -> Option<core::Block>;

	/// Provides a reading view into the current txhashset state as well as
	/// the required indexes for a consumer to rewind to a consistant state
	/// at the provided block hash.
	fn txhashset_read(&self, h: Hash) -> Option<TxHashSetRead>;

	/// Whether the node is ready to accept a new txhashset. If this isn't the
	/// case, the archive is provided without being requested and likely an
	/// attack attempt. This should be checked *before* downloading the whole
	/// state data.
	fn txhashset_receive_ready(&self) -> bool;

	/// Update txhashset downloading progress
	fn txhashset_download_update(
		&self,
		start_time: DateTime<Utc>,
		downloaded_size: u64,
		total_size: u64,
	) -> bool;

	/// Writes a reading view on a txhashset state that's been provided to us.
	/// If we're willing to accept that new state, the data stream will be
	/// read as a zip file, unzipped and the resulting state files should be
	/// rewound to the provided indexes.
	fn txhashset_write(&self, h: Hash, txhashset_data: File, peer_addr: SocketAddr) -> bool;
}

/// Additional methods required by the protocol that don't need to be
/// externally implemented.
pub trait NetAdapter: ChainAdapter {
	/// Find good peers we know with the provided capability and return their
	/// addresses.
	fn find_peer_addrs(&self, capab: Capabilities) -> Vec<SocketAddr>;

	/// A list of peers has been received from one of our peers.
	fn peer_addrs_received(&self, Vec<SocketAddr>);

	/// Heard total_difficulty from a connected peer (via ping/pong).
	fn peer_difficulty(&self, SocketAddr, Difficulty, u64);

	/// Is this peer currently banned?
	fn is_banned(&self, addr: SocketAddr) -> bool;
}
<|endoftext|>


<commit_before>use parser::obj::{
    ObjParser,
    ObjLine,
    FaceIndex,
};

use parser::mtl::{
    MtlLine,
    MtlParser
};

pub struct Obj {
    pub comments: Vec<ObjLine>,
    pub objects: Vec<ObjObject>,
}
impl Obj {
    pub fn create(filename: &'static str) -> Self {
        let mut obj = Obj{
            comments: Vec::new(),
            objects: Vec::new()
        };
        let parser = ObjParser::create(filename);

        let mut object = ObjObject::new();
        for line in parser {
            match line {
                ObjLine::ObjectName(name) => {
                    // new object encountered, when multiple objects exist
                    if object.name.is_some() {
                        obj.objects.push(object);
                        object = ObjObject::new();
                    }
                    object.name = Some(name);
                },
                ObjLine::MtlLib(name) => object.material = Some(name),
                ObjLine::Vertex(..) => object.vertices.push(line),
                ObjLine::VertexParam(..) => object.vertex_params.push(line),
                ObjLine::Face(..) => object.faces.push(line),
                ObjLine::Normal(..) => object.normals.push(line),
                ObjLine::TextureUVW(..) => object.texture_coords.push(line),
                _ => {}
            }
        }
        obj.objects.push(object);
        obj
    }
}

#[derive(Debug)]
pub struct ObjObject {
    pub name: Option<String>,
    pub material: Option<String>,
    vertices: Vec<ObjLine>,
    normals: Vec<ObjLine>,
    texture_coords: Vec<ObjLine>,
    vertex_params: Vec<ObjLine>,
    faces: Vec<ObjLine>,
}

impl ObjObject {
    pub fn new() -> Self {
        ObjObject{
            name: None,
            material: None,
            vertices: Vec::new(),
            normals: Vec::new(),
            texture_coords: Vec::new(),
            vertex_params: Vec::new(),
            faces: Vec::new(),
        }
    }
    pub fn vertices(&self) -> &Vec<ObjLine> { &self.vertices }
    pub fn vertex_params(&self) -> &Vec<ObjLine> { &self.vertex_params }
    pub fn normals(&self) -> &Vec<ObjLine> { &self.normals }
    pub fn texture_coords(&self) -> &Vec<ObjLine> { &self.texture_coords }
    pub fn material(&self) -> &Option<String> { &self.material }
    pub fn name(&self) -> &Option<String> { &self.name }
    pub fn faces(&self) -> &Vec<ObjLine> { &self.faces }

    #[inline]
    fn get_v_tuple(&self, face_index: &FaceIndex) -> (f32,f32,f32,f32) {
        let &FaceIndex(v, _, _) = face_index;
        match &self.vertices[(v as usize) - 1] {
            &ObjLine::Vertex(x,y,z,w) => (x,y,z,w.unwrap_or(1.0)),
            _ => panic!("not a vertex")
        }
    }

    #[inline]
    fn get_vt_tuple(&self, face_index: &FaceIndex) -> (f32,f32,f32) {
        let &FaceIndex(_, vt, _) = face_index;
        match &self.texture_coords[(vt.unwrap() as usize) - 1] {
            &ObjLine::TextureUVW(u,v,w) => (u,v,w.unwrap_or(0.0)),
            _ => panic!("not a vertex")
        }
    }

    #[inline]
    fn get_vn_tuple(&self, face_index: &FaceIndex) -> (f32,f32,f32) {
        let &FaceIndex(_, _, vn) = face_index;
        match &self.normals[(vn.unwrap() as usize) - 1] {
            &ObjLine::Normal(x,y,z) => (x,y,z),
            _ => panic!("not a vertex")
        }
    }

    #[inline]
    fn interleave_tuples(&self, id: &FaceIndex) -> (
        (f32, f32, f32, f32),
        (f32, f32, f32),
        (f32,f32,f32)
    ) {
        let vert = self.get_v_tuple(id);
        let text = self.get_vt_tuple(id);
        let norm = self.get_vn_tuple(id);
        (vert, text, norm)
    }

    pub fn interleaved(&self) -> Interleaved {
        let mut data = Interleaved{ v_vt_vn: Vec::new(), idx:Vec::new() };
        for i in 0usize..self.faces.len() {
            println!("{}", i);
            match &self.faces[i] {
                &ObjLine::Face(ref id1, ref id2, ref id3) => {
                    data.idx.push((id1.0 as usize) - 1);
                    data.idx.push((id2.0 as usize) - 1);
                    data.idx.push((id3.0 as usize) - 1);
                    data.v_vt_vn.push(self.interleave_tuples(id1));
                    data.v_vt_vn.push(self.interleave_tuples(id2));
                    data.v_vt_vn.push(self.interleave_tuples(id3));
                }
                _ => { panic!("Found something other than a ObjLine::Face in object.faces") }
            }
        }
        data
    }
}

pub struct Interleaved {
    pub v_vt_vn: Vec<((f32, f32, f32, f32), (f32, f32, f32), (f32,f32,f32))>,
    pub idx: Vec<usize>
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test] fn cube_format_interleaved() {
        let obj = Obj::create("assets/cube.obj");
        let interleaved = obj.objects[0].interleaved();
        println!("{:?}", obj.objects[0].faces());
        assert_eq!(obj.objects[0].faces().len(), 12);
        assert_eq!(interleaved.v_vt_vn.len(), interleaved.idx.len());
    }

    #[test] fn cube_obj_has_12_faces() { // Triangulated model, 12/2 = 6 quads
        let Obj{ objects: cube_objects, .. } = Obj::create("assets/cube.obj");
        assert_eq!(cube_objects[0].faces().len(), 12);
    }

    #[test] fn cube_obj_has_8_verts() {
        let Obj{ objects: cube_objects, .. } = Obj::create("assets/cube.obj");
        assert_eq!(cube_objects[0].vertices().len(), 8);
    }

    #[test] fn cube_obj_has_1_object() {
        let Obj{ objects: cube_objects, .. }  = Obj::create("assets/cube.obj");
        assert_eq!(cube_objects.len(), 1);
    }

    #[test] fn parses_separate_objects() {
        let Obj{ objects: cube_objects, .. } = Obj::create("assets/four_blue_cubes.obj");
        assert_eq!(cube_objects.len(), 4);
    }

    #[test] fn its_a_test() {

    }
}<commit_msg>fix indices<commit_after>use parser::obj::{
    ObjParser,
    ObjLine,
    FaceIndex,
};

use parser::mtl::{
    MtlLine,
    MtlParser
};

pub struct Obj {
    pub comments: Vec<ObjLine>,
    pub objects: Vec<ObjObject>,
}
impl Obj {
    pub fn create(filename: &'static str) -> Self {
        let mut obj = Obj{
            comments: Vec::new(),
            objects: Vec::new()
        };
        let parser = ObjParser::create(filename);

        let mut object = ObjObject::new();
        for line in parser {
            match line {
                ObjLine::ObjectName(name) => {
                    // new object encountered, when multiple objects exist
                    if object.name.is_some() {
                        obj.objects.push(object);
                        object = ObjObject::new();
                    }
                    object.name = Some(name);
                },
                ObjLine::MtlLib(name) => object.material = Some(name),
                ObjLine::Vertex(..) => object.vertices.push(line),
                ObjLine::VertexParam(..) => object.vertex_params.push(line),
                ObjLine::Face(..) => object.faces.push(line),
                ObjLine::Normal(..) => object.normals.push(line),
                ObjLine::TextureUVW(..) => object.texture_coords.push(line),
                _ => {}
            }
        }
        obj.objects.push(object);
        obj
    }
}

#[derive(Debug)]
pub struct ObjObject {
    pub name: Option<String>,
    pub material: Option<String>,
    vertices: Vec<ObjLine>,
    normals: Vec<ObjLine>,
    texture_coords: Vec<ObjLine>,
    vertex_params: Vec<ObjLine>,
    faces: Vec<ObjLine>,
}

impl ObjObject {
    pub fn new() -> Self {
        ObjObject{
            name: None,
            material: None,
            vertices: Vec::new(),
            normals: Vec::new(),
            texture_coords: Vec::new(),
            vertex_params: Vec::new(),
            faces: Vec::new(),
        }
    }
    pub fn vertices(&self) -> &Vec<ObjLine> { &self.vertices }
    pub fn vertex_params(&self) -> &Vec<ObjLine> { &self.vertex_params }
    pub fn normals(&self) -> &Vec<ObjLine> { &self.normals }
    pub fn texture_coords(&self) -> &Vec<ObjLine> { &self.texture_coords }
    pub fn material(&self) -> &Option<String> { &self.material }
    pub fn name(&self) -> &Option<String> { &self.name }
    pub fn faces(&self) -> &Vec<ObjLine> { &self.faces }

    #[inline]
    fn get_v_tuple(&self, face_index: &FaceIndex) -> (f32,f32,f32,f32) {
        let &FaceIndex(v, _, _) = face_index;
        match &self.vertices[(v as usize) - 1] {
            &ObjLine::Vertex(x,y,z,w) => (x,y,z,w.unwrap_or(1.0)),
            _ => panic!("not a vertex")
        }
    }

    #[inline]
    fn get_vt_tuple(&self, face_index: &FaceIndex) -> (f32,f32,f32) {
        let &FaceIndex(_, vt, _) = face_index;
        match &self.texture_coords[(vt.unwrap() as usize) - 1] {
            &ObjLine::TextureUVW(u,v,w) => (u,v,w.unwrap_or(0.0)),
            _ => panic!("not a vertex")
        }
    }

    #[inline]
    fn get_vn_tuple(&self, face_index: &FaceIndex) -> (f32,f32,f32) {
        let &FaceIndex(_, _, vn) = face_index;
        match &self.normals[(vn.unwrap() as usize) - 1] {
            &ObjLine::Normal(x,y,z) => (x,y,z),
            _ => panic!("not a vertex")
        }
    }

    #[inline]
    fn interleave_tuples(&self, id: &FaceIndex) -> (
        (f32, f32, f32, f32),
        (f32, f32, f32),
        (f32,f32,f32)
    ) {
        let vert = self.get_v_tuple(id);
        let text = self.get_vt_tuple(id);
        let norm = self.get_vn_tuple(id);
        (vert, text, norm)
    }

    pub fn interleaved(&self) -> Interleaved {
        let mut data = Interleaved{ v_vt_vn: Vec::new(), idx:Vec::new() };
        for i in 0usize..self.faces.len() {
            println!("{}", i);
            match &self.faces[i] {
                &ObjLine::Face(ref id1, ref id2, ref id3) => {
                    data.idx.push(i);
                    data.idx.push(i+1);
                    data.idx.push(i+2);
                    data.v_vt_vn.push(self.interleave_tuples(id1));
                    data.v_vt_vn.push(self.interleave_tuples(id2));
                    data.v_vt_vn.push(self.interleave_tuples(id3));
                }
                _ => { panic!("Found something other than a ObjLine::Face in object.faces") }
            }
        }
        data
    }
}

pub struct Interleaved {
    pub v_vt_vn: Vec<((f32, f32, f32, f32), (f32, f32, f32), (f32,f32,f32))>,
    pub idx: Vec<usize>
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test] fn cube_format_interleaved() {
        let obj = Obj::create("assets/cube.obj");
        let interleaved = obj.objects[0].interleaved();
        println!("{:?}", obj.objects[0].faces());
        assert_eq!(obj.objects[0].faces().len(), 12);
        assert_eq!(interleaved.v_vt_vn.len(), interleaved.idx.len());
    }

    #[test] fn cube_obj_has_12_faces() { // Triangulated model, 12/2 = 6 quads
        let Obj{ objects: cube_objects, .. } = Obj::create("assets/cube.obj");
        assert_eq!(cube_objects[0].faces().len(), 12);
    }

    #[test] fn cube_obj_has_8_verts() {
        let Obj{ objects: cube_objects, .. } = Obj::create("assets/cube.obj");
        assert_eq!(cube_objects[0].vertices().len(), 8);
    }

    #[test] fn cube_obj_has_1_object() {
        let Obj{ objects: cube_objects, .. }  = Obj::create("assets/cube.obj");
        assert_eq!(cube_objects.len(), 1);
    }

    #[test] fn parses_separate_objects() {
        let Obj{ objects: cube_objects, .. } = Obj::create("assets/four_blue_cubes.obj");
        assert_eq!(cube_objects.len(), 4);
    }

    #[test] fn its_a_test() {

    }
}<|endoftext|>


<commit_before>extern crate image;
extern crate clap;

use std::fs::File;
use std::path::Path;
use clap::{Arg, App};
use image::GenericImage;

fn rgb_comp<F>(a: &[u8], b: &[u8], cfunc: F) -> bool
    where F: Fn(&u8, &u8) -> bool {
    // comparision function; takes two u8 slices and compares their values element wise
    // before performing an all fold
    let mut v_bool = Vec::new();
    for (i,j) in a.iter().zip(b.iter()) {
        v_bool.push( cfunc(i,j) );
    }
    v_bool.iter().fold(true, |x, y| x & y)
}

fn main() {
    // setup clap argument parser
    let matches = App::new("rusty-transparent")
                    .version("0.0.1")
                    .author("edelsonc")
                    .about("Simple Image Background Transparency App")
                    .args( &[
                    Arg::from_usage("<INPUT> 'Sets the image file'"),
                    Arg::from_usage("[color], -c, --color [val1] [val2] [val3] 'Sets rgb value to compare'")
                    ])
                    .get_matches();

    // get matching values of arguments or substitute defaults
    let image_name = matches.value_of("INPUT").unwrap();
    let rgb_arg = match matches.values_of_lossy("color") {
        Some(v) => v,
        None => vec!["255".to_string(), "255".to_string(), "255".to_string()],
    };

    let rgb: Vec<u8> = rgb_arg.iter().map(|s| s.parse::<u8>().unwrap()).collect();

    // open image as a new dynamic image object
    let img = match image::open(&Path::new(image_name)) {
        Ok(p) => p,
        Err(e) => panic!("Not a valid image path or could not open image"),
    };

    let mut imgbuf = img.to_rgba();

    // iterate through the pixels of the image
    for pixel in imgbuf.pixels_mut() {
        if rgb_comp(&pixel.data[0..3], &rgb[..], |x,y| x == y) {
            pixel[3] = 0;
        }
    }

    // create and save to external file
    let mut fout = File::create(&Path::new("test.png")).unwrap();
    let _ = image::ImageRgba8(imgbuf).save(&mut fout, image::PNG);
}
<commit_msg>Added all of original functionality back 	* implements comparision choice 	* implements color choice 	* returns png with transparent_image.png<commit_after>extern crate image;
extern crate clap;

use std::fs::File;
use std::path::Path;
use clap::{Arg, App};
use image::GenericImage;

fn rgb_comp<F>(a: &[u8], b: &[u8], cfunc: F) -> bool
    where F: Fn(&u8, &u8) -> bool {
    // comparision function; takes two u8 slices and compares their values element wise
    // before performing an all fold
    let mut v_bool = Vec::new();
    for (i,j) in a.iter().zip(b.iter()) {
        v_bool.push( cfunc(i,j) );
    }
    v_bool.iter().fold(true, |x, y| x & y)
}

// operator functions to be returned based on chosen operator
fn eq (x: &u8, y: &u8) -> bool { x == y }
fn gt (x: &u8, y: &u8) -> bool { x > y }
fn lt (x: &u8, y: &u8) -> bool { x < y }

fn comp_func(op: &str) -> fn(&u8, &u8) -> bool {
    // function to select operator functon
    if op == "eq" {
        eq
    } else if op == "gt" {
        gt
    } else {
        lt
    }
}

fn main() {
    // setup clap argument parser
    let matches = App::new("rusty-transparent")
                    .version("0.0.1")
                    .author("edelsonc")
                    .about("Simple Image Background Transparency App")
                    .args( &[
                    Arg::from_usage("<INPUT> 'Sets the image file'"),
                    Arg::from_usage("[color], -c, --color [val1] [val2] [val3] 'Sets rgb value to compare'"),
                    Arg::from_usage("[operator] -o --operator [op] 'Comparison operator'")
                    .possible_values(&["eq", "lt", "gt"])
                    .default_value("eq")
                    ])
                    .get_matches();

    // get matching values of arguments or substitute defaults
    let image_name = matches.value_of("INPUT").unwrap();
    let rgb = match matches.values_of_lossy("color") {
        Some(v) => v.iter().map(|s| s.parse::<u8>().unwrap()).collect(),
        None => vec![255u8, 255u8, 255u8],
    };

    // turn matching operator argument into comparision function
    let comp_op = matches.value_of("operator").unwrap(); // safe with default
    let cfunc = comp_func(&comp_op);

    // open image as a new dynamic image object
    let img = match image::open(&Path::new(image_name)) {
        Ok(p) => p,
        Err(e) => panic!("Not a valid image path or could not open image"),
    };

    let mut imgbuf = img.to_rgba();

    // iterate through the pixels of the image
    for pixel in imgbuf.pixels_mut() {
        if rgb_comp(&pixel.data[0..3], &rgb[..], cfunc) {
            pixel[3] = 0;
        }
    }

    // create and save to external file
    // following only safe since image_name is a valid path
    let no_ext = Path::new(image_name)
        .file_stem().unwrap()
        .to_str().unwrap();
    let new_title = format!("transparent_{}.png", no_ext);
    let mut fout = File::create(&Path::new(&new_title)).unwrap();
    let _ = image::ImageRgba8(imgbuf).save(&mut fout, image::PNG);
}

<|endoftext|>


<commit_before>use crate::{return_variant, ErrorCode, ReturnVariant};

use core::mem::transmute;

/// The response type from the [`command`](crate::Syscalls::command) syscall.
/// Can represent a success or a failure with or without associated data.
///
/// After a syscall is made, registers `r1`-`r3` contain the output as
/// described by [TRD 104][trd-104]. Some syscalls only return success/failure,
/// while others provide associated data. This is done by placing the _return
/// variant_ in `r0`, which specifies how the output registers should be
/// interpreted. For syscalls other than `command`, the possible output
/// variants are fixed; you always know which variants are expected given the
/// syscall class.
///
/// However, the `command` syscall is flexible - there must be one success
/// variant and one failure variant for a given driver/command ID, but
/// which variants those are, and what data is expected, cannot be checked
/// statically. Capsules and userspace APIs must agree on the expected
/// variants for success and failure.
///
/// # Example
///
/// This uses the [`to_result`] method to implicitly check variants and convert
/// to a `Result`.
///
/// ```ignore
/// let res: Result<(u32, u32), ErrorCode> = Syscalls::command(314, 1, 1, 2).to_result();
/// match res {
///     Ok((val1, val2)) => {
///         // Success with associated data in val1, val2.
///     }
///     Err(ErrorCode::BadRVal) => {
///         // Incorrect return variant! We may choose to handle this
///         // explicitly or propagate upwards without branching.
///     }
///     Err(ec) => {
///         // The driver returned an error (or it doesn't exist).
///     }
/// }
/// ```
///
/// This uses the `get_*` methods to check the variants explicitly and extract
/// the associated data.
///
/// ```ignore
/// let command_return = Syscalls::command(314, 1, 1, 2);
/// if let Some((val1, val2)) = command_return.get_success_2_u32() {
///     // If there was a success, there is an associated data (u32, u32).
/// } else if let Some(error_code) = command_return.get_failure() {
///     // If there was a failure, there's no associated data and we only
///     // have an error code.
/// } else {
///     // Incorrect return variant! If this occurs, your capsule and userspace
///     // API do not agree on what the return variants should be.
///     // An application may want to panic in this case to catch this early.
/// }
/// ```
///
/// [trd-104]: https://github.com/tock/tock/blob/master/doc/reference/trd104-syscalls.md#32-return-values
#[must_use = "this `CommandReturn` may represent an error, which should be handled"]
#[derive(Clone, Copy, Debug)]
pub struct CommandReturn {
    return_variant: ReturnVariant,

    // Safety invariant on r1: If return_variant is failure variant, r1 must be
    // a valid ErrorCode.
    r1: u32,
    r2: u32,
    r3: u32,
}

impl CommandReturn {
    /// # Safety
    /// If return_variant is a failure variant, r1 must be a valid ErrorCode.
    pub unsafe fn new(return_variant: ReturnVariant, r1: u32, r2: u32, r3: u32) -> Self {
        CommandReturn {
            return_variant,
            r1,
            r2,
            r3,
        }
    }

    /// Returns true if this CommandReturn is of type Failure. Note that this
    /// does not return true for other failure types, such as Failure with u32.
    pub fn is_failure(&self) -> bool {
        self.return_variant == return_variant::FAILURE
    }

    /// Returns true if this CommandReturn is of type Failure with u32.
    pub fn is_failure_u32(&self) -> bool {
        self.return_variant == return_variant::FAILURE_U32
    }

    /// Returns true if this CommandReturn is of type Failure with 2 u32.
    pub fn is_failure_2_u32(&self) -> bool {
        self.return_variant == return_variant::FAILURE_2_U32
    }

    /// Returns true if this CommandReturn is of type Failure with u64.
    pub fn is_failure_u64(&self) -> bool {
        self.return_variant == return_variant::FAILURE_U64
    }

    /// Returns true if this CommandReturn is of type Success. Note that this
    /// does not return true for other success types, such as Success with u32.
    pub fn is_success(&self) -> bool {
        self.return_variant == return_variant::SUCCESS
    }

    /// Returns true if this CommandReturn is of type Success with u32.
    pub fn is_success_u32(&self) -> bool {
        self.return_variant == return_variant::SUCCESS_U32
    }

    /// Returns true if this CommandReturn is of type Success with 2 u32.
    pub fn is_success_2_u32(&self) -> bool {
        self.return_variant == return_variant::SUCCESS_2_U32
    }

    /// Returns true if this CommandReturn is of type Success with u64.
    pub fn is_success_u64(&self) -> bool {
        self.return_variant == return_variant::SUCCESS_U64
    }

    /// Returns true if this CommandReturn is of type Success with 3 u32.
    pub fn is_success_3_u32(&self) -> bool {
        self.return_variant == return_variant::SUCCESS_3_U32
    }

    /// Returns true if this CommandReturn is of type Success with u32 and u64.
    pub fn is_success_u32_u64(&self) -> bool {
        self.return_variant == return_variant::SUCCESS_U32_U64
    }

    /// Returns the error code if this CommandReturn is of type Failure.
    pub fn get_failure(&self) -> Option<ErrorCode> {
        if !self.is_failure() {
            return None;
        }
        Some(unsafe { transmute(self.r1 as u16) })
    }

    /// Returns the error code and value if this CommandReturn is of type
    /// Failure with u32.
    pub fn get_failure_u32(&self) -> Option<(ErrorCode, u32)> {
        if !self.is_failure_u32() {
            return None;
        }
        Some((unsafe { transmute(self.r1 as u16) }, self.r2))
    }

    /// Returns the error code and return values if this CommandReturn is of
    /// type Failure with 2 u32.
    pub fn get_failure_2_u32(&self) -> Option<(ErrorCode, u32, u32)> {
        if !self.is_failure_2_u32() {
            return None;
        }
        Some((unsafe { transmute(self.r1 as u16) }, self.r2, self.r3))
    }

    /// Returns the error code and return value if this CommandReturn is of type
    /// Failure with u64.
    pub fn get_failure_u64(&self) -> Option<(ErrorCode, u64)> {
        if !self.is_failure_u64() {
            return None;
        }
        Some((
            unsafe { transmute(self.r1 as u16) },
            self.r2 as u64 + ((self.r3 as u64) << 32),
        ))
    }

    /// Returns the value if this CommandReturn is of type Success with u32.
    pub fn get_success_u32(&self) -> Option<u32> {
        if !self.is_success_u32() {
            return None;
        }
        Some(self.r1)
    }

    /// Returns the values if this CommandReturn is of type Success with 2 u32.
    pub fn get_success_2_u32(&self) -> Option<(u32, u32)> {
        if !self.is_success_2_u32() {
            return None;
        }
        Some((self.r1, self.r2))
    }

    /// Returns the value if this CommandReturn is of type Success with u64.
    pub fn get_success_u64(&self) -> Option<u64> {
        if !self.is_success_u64() {
            return None;
        }
        Some(self.r1 as u64 + ((self.r2 as u64) << 32))
    }

    /// Returns the values if this CommandReturn is of type Success with 3 u32.
    pub fn get_success_3_u32(&self) -> Option<(u32, u32, u32)> {
        if !self.is_success_3_u32() {
            return None;
        }
        Some((self.r1, self.r2, self.r3))
    }

    /// Returns the values if this CommandReturn is of type Success with u32 and
    /// u64.
    pub fn get_success_u32_u64(&self) -> Option<(u32, u64)> {
        if !self.is_success_u32_u64() {
            return None;
        }
        Some((self.r1, self.r2 as u64 + ((self.r3 as u64) << 32)))
    }

    /// Returns the register values used to create this command.
    pub fn raw_values(&self) -> (ReturnVariant, u32, u32, u32) {
        (self.return_variant, self.r1, self.r2, self.r3)
    }

    /// Returns the return variant of this command.
    pub fn return_variant(&self) -> ReturnVariant {
        self.return_variant
    }

    /// Interprets this `CommandReturn` as a `Result`, checking the success and
    /// failure variants, as well as extracting the relevant data.
    ///
    /// If neither the success or failure variants match what is required by
    /// `T` and `E`, this function will return `Err(ErrorCode::BadRVal)`.
    /// If `E` contains non-`ErrorCode` data in this case, the data will be 0.
    ///
    /// It is recommended to use type ascription or `::<>` to make the types
    /// for `T` and `E` explicit at call-site.
    pub fn to_result<T, E>(self) -> Result<T, E>
    where
        T: SuccessData,
        E: FailureData,
    {
        let (return_variant, r1, mut r2, mut r3) = self.raw_values();
        if return_variant == T::RETURN_VARIANT {
            return Ok(T::from_raw_values(r1, r2, r3));
        }
        let ec: ErrorCode = if return_variant == E::RETURN_VARIANT {
            // Safety: E::RETURN_VARIANT must be a failure variant, and
            // failure variants must contain a valid ErrorCode in r1.
            unsafe { core::mem::transmute(r1 as u16) }
        } else {
            r2 = 0;
            r3 = 0;
            ErrorCode::BadRVal
        };
        Err(E::from_raw_values(ec, r2, r3))
    }
}

mod sealed {
    pub trait Sealed {}
}

/// Output from a successful `command` syscall.
pub trait SuccessData: sealed::Sealed {
    const RETURN_VARIANT: ReturnVariant;

    /// Constructs the success data given the raw register values.
    fn from_raw_values(r1: u32, r2: u32, r3: u32) -> Self;
}

impl sealed::Sealed for () {}
impl SuccessData for () {
    const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS;

    fn from_raw_values(_r1: u32, _r2: u32, _r3: u32) -> Self {}
}
impl sealed::Sealed for u32 {}
impl SuccessData for u32 {
    /// The return variant for this success type, stored in `r0` after
    /// performing a `command` syscall.
    const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_U32;

    fn from_raw_values(r1: u32, _r2: u32, _r3: u32) -> Self {
        r1
    }
}
impl sealed::Sealed for u64 {}
impl SuccessData for u64 {
    const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_U64;

    fn from_raw_values(r1: u32, r2: u32, _r3: u32) -> Self {
        r1 as u64 | ((r2 as u64) << 32)
    }
}
impl sealed::Sealed for (u32, u32) {}
impl SuccessData for (u32, u32) {
    const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_2_U32;

    fn from_raw_values(r1: u32, r2: u32, _r3: u32) -> Self {
        (r1, r2)
    }
}
impl sealed::Sealed for (u32, u64) {}
impl SuccessData for (u32, u64) {
    const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_U32_U64;

    fn from_raw_values(r1: u32, r2: u32, r3: u32) -> Self {
        (r1, r2 as u64 | ((r3 as u64) << 32))
    }
}
impl sealed::Sealed for (u32, u32, u32) {}
impl SuccessData for (u32, u32, u32) {
    const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_3_U32;

    fn from_raw_values(r1: u32, r2: u32, r3: u32) -> Self {
        (r1, r2, r3)
    }
}

/// Output from a failed `command` syscall.
pub unsafe trait FailureData: sealed::Sealed {
    /// The return variant for this failure type, stored in `r0` after
    /// performing a `command` syscall.
    ///
    /// # Safety
    /// This must represent a failure variant, such that `r1` will always be
    /// a valid [`ErrorCode`].
    const RETURN_VARIANT: ReturnVariant;

    /// Constructs the error data given the raw register values.
    fn from_raw_values(r1: ErrorCode, r2: u32, r3: u32) -> Self;
}

impl sealed::Sealed for ErrorCode {}
unsafe impl FailureData for ErrorCode {
    const RETURN_VARIANT: ReturnVariant = return_variant::FAILURE;

    fn from_raw_values(r1: ErrorCode, _r2: u32, _r3: u32) -> Self {
        r1
    }
}
impl sealed::Sealed for (ErrorCode, u32) {}
unsafe impl FailureData for (ErrorCode, u32) {
    const RETURN_VARIANT: ReturnVariant = return_variant::FAILURE_U32;

    fn from_raw_values(r1: ErrorCode, r2: u32, _r3: u32) -> Self {
        (r1, r2)
    }
}
impl sealed::Sealed for (ErrorCode, u32, u32) {}
unsafe impl FailureData for (ErrorCode, u32, u32) {
    const RETURN_VARIANT: ReturnVariant = return_variant::FAILURE_2_U32;

    fn from_raw_values(r1: ErrorCode, r2: u32, r3: u32) -> Self {
        (r1, r2, r3)
    }
}
impl sealed::Sealed for (ErrorCode, u64) {}
unsafe impl FailureData for (ErrorCode, u64) {
    const RETURN_VARIANT: ReturnVariant = return_variant::FAILURE_U64;

    fn from_raw_values(r1: ErrorCode, r2: u32, r3: u32) -> Self {
        (r1, r2 as u64 | ((r3 as u64) << 32))
    }
}
<commit_msg>Correct the docstring for SuccessData::RETURN_VARIANT<commit_after>use crate::{return_variant, ErrorCode, ReturnVariant};

use core::mem::transmute;

/// The response type from the [`command`](crate::Syscalls::command) syscall.
/// Can represent a success or a failure with or without associated data.
///
/// After a syscall is made, registers `r1`-`r3` contain the output as
/// described by [TRD 104][trd-104]. Some syscalls only return success/failure,
/// while others provide associated data. This is done by placing the _return
/// variant_ in `r0`, which specifies how the output registers should be
/// interpreted. For syscalls other than `command`, the possible output
/// variants are fixed; you always know which variants are expected given the
/// syscall class.
///
/// However, the `command` syscall is flexible - there must be one success
/// variant and one failure variant for a given driver/command ID, but
/// which variants those are, and what data is expected, cannot be checked
/// statically. Capsules and userspace APIs must agree on the expected
/// variants for success and failure.
///
/// # Example
///
/// This uses the [`to_result`] method to implicitly check variants and convert
/// to a `Result`.
///
/// ```ignore
/// let res: Result<(u32, u32), ErrorCode> = Syscalls::command(314, 1, 1, 2).to_result();
/// match res {
///     Ok((val1, val2)) => {
///         // Success with associated data in val1, val2.
///     }
///     Err(ErrorCode::BadRVal) => {
///         // Incorrect return variant! We may choose to handle this
///         // explicitly or propagate upwards without branching.
///     }
///     Err(ec) => {
///         // The driver returned an error (or it doesn't exist).
///     }
/// }
/// ```
///
/// This uses the `get_*` methods to check the variants explicitly and extract
/// the associated data.
///
/// ```ignore
/// let command_return = Syscalls::command(314, 1, 1, 2);
/// if let Some((val1, val2)) = command_return.get_success_2_u32() {
///     // If there was a success, there is an associated data (u32, u32).
/// } else if let Some(error_code) = command_return.get_failure() {
///     // If there was a failure, there's no associated data and we only
///     // have an error code.
/// } else {
///     // Incorrect return variant! If this occurs, your capsule and userspace
///     // API do not agree on what the return variants should be.
///     // An application may want to panic in this case to catch this early.
/// }
/// ```
///
/// [trd-104]: https://github.com/tock/tock/blob/master/doc/reference/trd104-syscalls.md#32-return-values
#[must_use = "this `CommandReturn` may represent an error, which should be handled"]
#[derive(Clone, Copy, Debug)]
pub struct CommandReturn {
    return_variant: ReturnVariant,

    // Safety invariant on r1: If return_variant is failure variant, r1 must be
    // a valid ErrorCode.
    r1: u32,
    r2: u32,
    r3: u32,
}

impl CommandReturn {
    /// # Safety
    /// If return_variant is a failure variant, r1 must be a valid ErrorCode.
    pub unsafe fn new(return_variant: ReturnVariant, r1: u32, r2: u32, r3: u32) -> Self {
        CommandReturn {
            return_variant,
            r1,
            r2,
            r3,
        }
    }

    /// Returns true if this CommandReturn is of type Failure. Note that this
    /// does not return true for other failure types, such as Failure with u32.
    pub fn is_failure(&self) -> bool {
        self.return_variant == return_variant::FAILURE
    }

    /// Returns true if this CommandReturn is of type Failure with u32.
    pub fn is_failure_u32(&self) -> bool {
        self.return_variant == return_variant::FAILURE_U32
    }

    /// Returns true if this CommandReturn is of type Failure with 2 u32.
    pub fn is_failure_2_u32(&self) -> bool {
        self.return_variant == return_variant::FAILURE_2_U32
    }

    /// Returns true if this CommandReturn is of type Failure with u64.
    pub fn is_failure_u64(&self) -> bool {
        self.return_variant == return_variant::FAILURE_U64
    }

    /// Returns true if this CommandReturn is of type Success. Note that this
    /// does not return true for other success types, such as Success with u32.
    pub fn is_success(&self) -> bool {
        self.return_variant == return_variant::SUCCESS
    }

    /// Returns true if this CommandReturn is of type Success with u32.
    pub fn is_success_u32(&self) -> bool {
        self.return_variant == return_variant::SUCCESS_U32
    }

    /// Returns true if this CommandReturn is of type Success with 2 u32.
    pub fn is_success_2_u32(&self) -> bool {
        self.return_variant == return_variant::SUCCESS_2_U32
    }

    /// Returns true if this CommandReturn is of type Success with u64.
    pub fn is_success_u64(&self) -> bool {
        self.return_variant == return_variant::SUCCESS_U64
    }

    /// Returns true if this CommandReturn is of type Success with 3 u32.
    pub fn is_success_3_u32(&self) -> bool {
        self.return_variant == return_variant::SUCCESS_3_U32
    }

    /// Returns true if this CommandReturn is of type Success with u32 and u64.
    pub fn is_success_u32_u64(&self) -> bool {
        self.return_variant == return_variant::SUCCESS_U32_U64
    }

    /// Returns the error code if this CommandReturn is of type Failure.
    pub fn get_failure(&self) -> Option<ErrorCode> {
        if !self.is_failure() {
            return None;
        }
        Some(unsafe { transmute(self.r1 as u16) })
    }

    /// Returns the error code and value if this CommandReturn is of type
    /// Failure with u32.
    pub fn get_failure_u32(&self) -> Option<(ErrorCode, u32)> {
        if !self.is_failure_u32() {
            return None;
        }
        Some((unsafe { transmute(self.r1 as u16) }, self.r2))
    }

    /// Returns the error code and return values if this CommandReturn is of
    /// type Failure with 2 u32.
    pub fn get_failure_2_u32(&self) -> Option<(ErrorCode, u32, u32)> {
        if !self.is_failure_2_u32() {
            return None;
        }
        Some((unsafe { transmute(self.r1 as u16) }, self.r2, self.r3))
    }

    /// Returns the error code and return value if this CommandReturn is of type
    /// Failure with u64.
    pub fn get_failure_u64(&self) -> Option<(ErrorCode, u64)> {
        if !self.is_failure_u64() {
            return None;
        }
        Some((
            unsafe { transmute(self.r1 as u16) },
            self.r2 as u64 + ((self.r3 as u64) << 32),
        ))
    }

    /// Returns the value if this CommandReturn is of type Success with u32.
    pub fn get_success_u32(&self) -> Option<u32> {
        if !self.is_success_u32() {
            return None;
        }
        Some(self.r1)
    }

    /// Returns the values if this CommandReturn is of type Success with 2 u32.
    pub fn get_success_2_u32(&self) -> Option<(u32, u32)> {
        if !self.is_success_2_u32() {
            return None;
        }
        Some((self.r1, self.r2))
    }

    /// Returns the value if this CommandReturn is of type Success with u64.
    pub fn get_success_u64(&self) -> Option<u64> {
        if !self.is_success_u64() {
            return None;
        }
        Some(self.r1 as u64 + ((self.r2 as u64) << 32))
    }

    /// Returns the values if this CommandReturn is of type Success with 3 u32.
    pub fn get_success_3_u32(&self) -> Option<(u32, u32, u32)> {
        if !self.is_success_3_u32() {
            return None;
        }
        Some((self.r1, self.r2, self.r3))
    }

    /// Returns the values if this CommandReturn is of type Success with u32 and
    /// u64.
    pub fn get_success_u32_u64(&self) -> Option<(u32, u64)> {
        if !self.is_success_u32_u64() {
            return None;
        }
        Some((self.r1, self.r2 as u64 + ((self.r3 as u64) << 32)))
    }

    /// Returns the register values used to create this command.
    pub fn raw_values(&self) -> (ReturnVariant, u32, u32, u32) {
        (self.return_variant, self.r1, self.r2, self.r3)
    }

    /// Returns the return variant of this command.
    pub fn return_variant(&self) -> ReturnVariant {
        self.return_variant
    }

    /// Interprets this `CommandReturn` as a `Result`, checking the success and
    /// failure variants, as well as extracting the relevant data.
    ///
    /// If neither the success or failure variants match what is required by
    /// `T` and `E`, this function will return `Err(ErrorCode::BadRVal)`.
    /// If `E` contains non-`ErrorCode` data in this case, the data will be 0.
    ///
    /// It is recommended to use type ascription or `::<>` to make the types
    /// for `T` and `E` explicit at call-site.
    pub fn to_result<T, E>(self) -> Result<T, E>
    where
        T: SuccessData,
        E: FailureData,
    {
        let (return_variant, r1, mut r2, mut r3) = self.raw_values();
        if return_variant == T::RETURN_VARIANT {
            return Ok(T::from_raw_values(r1, r2, r3));
        }
        let ec: ErrorCode = if return_variant == E::RETURN_VARIANT {
            // Safety: E::RETURN_VARIANT must be a failure variant, and
            // failure variants must contain a valid ErrorCode in r1.
            unsafe { core::mem::transmute(r1 as u16) }
        } else {
            r2 = 0;
            r3 = 0;
            ErrorCode::BadRVal
        };
        Err(E::from_raw_values(ec, r2, r3))
    }
}

mod sealed {
    pub trait Sealed {}
}

/// Output from a successful `command` syscall.
pub trait SuccessData: sealed::Sealed {
    /// The return variant for this success type, stored in `r0` after
    /// performing a `command` syscall.
    const RETURN_VARIANT: ReturnVariant;

    /// Constructs the success data given the raw register values.
    fn from_raw_values(r1: u32, r2: u32, r3: u32) -> Self;
}

impl sealed::Sealed for () {}
impl SuccessData for () {
    const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS;

    fn from_raw_values(_r1: u32, _r2: u32, _r3: u32) -> Self {}
}
impl sealed::Sealed for u32 {}
impl SuccessData for u32 {
    const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_U32;

    fn from_raw_values(r1: u32, _r2: u32, _r3: u32) -> Self {
        r1
    }
}
impl sealed::Sealed for u64 {}
impl SuccessData for u64 {
    const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_U64;

    fn from_raw_values(r1: u32, r2: u32, _r3: u32) -> Self {
        r1 as u64 | ((r2 as u64) << 32)
    }
}
impl sealed::Sealed for (u32, u32) {}
impl SuccessData for (u32, u32) {
    const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_2_U32;

    fn from_raw_values(r1: u32, r2: u32, _r3: u32) -> Self {
        (r1, r2)
    }
}
impl sealed::Sealed for (u32, u64) {}
impl SuccessData for (u32, u64) {
    const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_U32_U64;

    fn from_raw_values(r1: u32, r2: u32, r3: u32) -> Self {
        (r1, r2 as u64 | ((r3 as u64) << 32))
    }
}
impl sealed::Sealed for (u32, u32, u32) {}
impl SuccessData for (u32, u32, u32) {
    const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_3_U32;

    fn from_raw_values(r1: u32, r2: u32, r3: u32) -> Self {
        (r1, r2, r3)
    }
}

/// Output from a failed `command` syscall.
pub unsafe trait FailureData: sealed::Sealed {
    /// The return variant for this failure type, stored in `r0` after
    /// performing a `command` syscall.
    ///
    /// # Safety
    /// This must represent a failure variant, such that `r1` will always be
    /// a valid [`ErrorCode`].
    const RETURN_VARIANT: ReturnVariant;

    /// Constructs the error data given the raw register values.
    fn from_raw_values(r1: ErrorCode, r2: u32, r3: u32) -> Self;
}

impl sealed::Sealed for ErrorCode {}
unsafe impl FailureData for ErrorCode {
    const RETURN_VARIANT: ReturnVariant = return_variant::FAILURE;

    fn from_raw_values(r1: ErrorCode, _r2: u32, _r3: u32) -> Self {
        r1
    }
}
impl sealed::Sealed for (ErrorCode, u32) {}
unsafe impl FailureData for (ErrorCode, u32) {
    const RETURN_VARIANT: ReturnVariant = return_variant::FAILURE_U32;

    fn from_raw_values(r1: ErrorCode, r2: u32, _r3: u32) -> Self {
        (r1, r2)
    }
}
impl sealed::Sealed for (ErrorCode, u32, u32) {}
unsafe impl FailureData for (ErrorCode, u32, u32) {
    const RETURN_VARIANT: ReturnVariant = return_variant::FAILURE_2_U32;

    fn from_raw_values(r1: ErrorCode, r2: u32, r3: u32) -> Self {
        (r1, r2, r3)
    }
}
impl sealed::Sealed for (ErrorCode, u64) {}
unsafe impl FailureData for (ErrorCode, u64) {
    const RETURN_VARIANT: ReturnVariant = return_variant::FAILURE_U64;

    fn from_raw_values(r1: ErrorCode, r2: u32, r3: u32) -> Self {
        (r1, r2 as u64 | ((r3 as u64) << 32))
    }
}
<|endoftext|>


<commit_before>use crate::errors::OscError;
use crate::types::{
    Result
};
use crate::regex::Regex;

/// Check if the address of an OSC method is valid
pub fn validate_method_address(addr: &String) -> Result<()>
{
    if !addr.is_ascii() {
        return Err(OscError::BadAddress("Address must only contain ASCII characters"));
    }
    if addr.len() < 1 {
        return Err(OscError::BadAddress("Address must be at least 1 character long"));
    }
    let mut chars = addr.chars();

    // Check if address starts with '/'
    let first = chars.next().unwrap();
    if first != '/' {
        return Err(OscError::BadAddress("Address must start with '/'"));
    }

    // Check if address ends with '/'
    if addr.ends_with('/') {
        return Err(OscError::BadAddress("Address must not end with '/'"));
    }

    // Check if address contains illegal characters
    for char in chars
    {
        if ((char as u8) < 0x20) | ((char as u8) > 0x7E) {
            return Err(OscError::BadAddress("Address may only contain printable ASCII characters"));
        }
        if " #*,?[]{}".chars().any(|x| char == x) {
            return Err(OscError::BadAddress("Address may not contain any of the following characters: ' #*,?[]{}'"));
        }
    }

    return Ok(());
}

/// Check if the address of an OSC message is valid
pub fn validate_message_address(addr: &String) -> Result<()>
{
    if !addr.is_ascii() {
        return Err(OscError::BadAddress("Address must only contain ASCII characters"));
    }
    if addr.len() < 1 {
        return Err(OscError::BadAddress("Address must be at least 1 character long"));
    }
    let mut chars = addr.chars();

    // Check if address starts with '/'
    let first = chars.next().unwrap();
    if first != '/' {
        return Err(OscError::BadAddress("Address must start with '/'"));
    }

    // Check if address ends with '/'
    if addr.ends_with('/') {
        return Err(OscError::BadAddress("Address must not end with '/'"));
    }

    // Validate rest of address
    let mut in_character_range = false;
    let mut in_string_list = false;
    for char in chars
    {
        if ((char as u8) < 0x20) | ((char as u8) > 0x7E) {
            return Err(OscError::BadAddress("Address may only contain printable ASCII characters"));
        }
        if " #".chars().any(|x| char == x) {
            return Err(OscError::BadAddress("Address may not contain any of the following characters: ' #'"));
        }
        if !in_string_list && char == ',' {
            return Err(OscError::BadAddress("Address may not contain any of the following characters outside of string lists: ','"));
        }
        if char == '[' {
            in_character_range = true;
            if in_string_list {
                return Err(OscError::BadAddress("Can not start a character range (square brackets) within string list (curly brackets)"));
            }
        }
        if (char == '/') & in_character_range {
            return Err(OscError::BadAddress("Character range (square brackets) was started but not closed before the next address part started"));
        }
        if char == ']' {
            in_character_range = false;
        }
        if char == '{' {
            in_string_list = true;
        }
        if (char == '/') & in_string_list {
            return Err(OscError::BadAddress("String list (curly brackets) was started but not closed before the next address part started"));
        }
        if char == '}' {
            in_string_list = false;
            if in_character_range {
                return Err(OscError::BadAddress("Can not start a string list (curly brackets) within character range (square brackets)"));
            }
        }
    }
    if in_character_range {
        return Err(OscError::BadAddress("Character range (square brackets) was started but not closed before the end of the address"));
    }
    if in_string_list {
        return Err(OscError::BadAddress("String list (curly brackets) was started but not closed before the end of the address"));
    }

    return Ok(());
}

/// Match a single part of two OSC addresses
fn match_part(message_part: &str, method_part: &str) -> bool
{
    // direct match
    if message_part == method_part {
        return true;
    }

    // Use regex for everything else
    let mut pattern = message_part.to_string()
        .replace("*", "\\w*")
        .replace("?", "\\w")
        .replace("[!", "[^")
        .replace(",", ")|(?:")
        .replace("{", "(?:")
        .replace("}", ")");

    // Anchor the pattern to beginning and end of string
    pattern = format!("^{}$", pattern);

    let re = Regex::new(pattern.as_str()).unwrap();

    re.is_match(method_part)
}

/// Check if a message address matches a method address
pub fn match_address(message_addr: &String, method_addr: &String) -> Result<bool>
{
    match validate_message_address(message_addr) {
        Ok(()) => {},
        Err(e) => return Err(e)
    }
    match validate_method_address(method_addr) {
        Ok(()) => {},
        Err(e) => return Err(e)
    }

    let message_addr_parts: Vec<&str> = message_addr.split('/').collect();
    let method_addr_parts: Vec<&str> = method_addr.split('/').collect();

    if message_addr_parts.len() != method_addr_parts.len() {
        // Both addresses must have the same amount of parts
        return Ok(false);
    }

    for i in 1..message_addr_parts.len() {
        //println!("Parts: '{}' '{}' {}", message_addr_parts[i], method_addr_parts[i], match_part(message_addr_parts[i], method_addr_parts[i]));
        if !match_part(message_addr_parts[i], method_addr_parts[i]) {
            return Ok(false);
        }
    }

    Ok(true)
}<commit_msg>Use str instead of String<commit_after>use crate::errors::OscError;
use crate::types::{
    Result
};
use crate::regex::Regex;

/// Check if the address of an OSC method is valid
pub fn validate_method_address(addr: &str) -> Result<()>
{
    if !addr.is_ascii() {
        return Err(OscError::BadAddress("Address must only contain ASCII characters"));
    }
    if addr.len() < 1 {
        return Err(OscError::BadAddress("Address must be at least 1 character long"));
    }
    let mut chars = addr.chars();

    // Check if address starts with '/'
    let first = chars.next().unwrap();
    if first != '/' {
        return Err(OscError::BadAddress("Address must start with '/'"));
    }

    // Check if address ends with '/'
    if addr.ends_with('/') {
        return Err(OscError::BadAddress("Address must not end with '/'"));
    }

    // Check if address contains illegal characters
    for char in chars
    {
        if ((char as u8) < 0x20) | ((char as u8) > 0x7E) {
            return Err(OscError::BadAddress("Address may only contain printable ASCII characters"));
        }
        if " #*,?[]{}".chars().any(|x| char == x) {
            return Err(OscError::BadAddress("Address may not contain any of the following characters: ' #*,?[]{}'"));
        }
    }

    return Ok(());
}

/// Check if the address of an OSC message is valid
pub fn validate_message_address(addr: &str) -> Result<()>
{
    if !addr.is_ascii() {
        return Err(OscError::BadAddress("Address must only contain ASCII characters"));
    }
    if addr.len() < 1 {
        return Err(OscError::BadAddress("Address must be at least 1 character long"));
    }
    let mut chars = addr.chars();

    // Check if address starts with '/'
    let first = chars.next().unwrap();
    if first != '/' {
        return Err(OscError::BadAddress("Address must start with '/'"));
    }

    // Check if address ends with '/'
    if addr.ends_with('/') {
        return Err(OscError::BadAddress("Address must not end with '/'"));
    }

    // Validate rest of address
    let mut in_character_range = false;
    let mut in_string_list = false;
    for char in chars
    {
        if ((char as u8) < 0x20) | ((char as u8) > 0x7E) {
            return Err(OscError::BadAddress("Address may only contain printable ASCII characters"));
        }
        if " #".chars().any(|x| char == x) {
            return Err(OscError::BadAddress("Address may not contain any of the following characters: ' #'"));
        }
        if !in_string_list && char == ',' {
            return Err(OscError::BadAddress("Address may not contain any of the following characters outside of string lists: ','"));
        }
        if char == '[' {
            in_character_range = true;
            if in_string_list {
                return Err(OscError::BadAddress("Can not start a character range (square brackets) within string list (curly brackets)"));
            }
        }
        if (char == '/') & in_character_range {
            return Err(OscError::BadAddress("Character range (square brackets) was started but not closed before the next address part started"));
        }
        if char == ']' {
            in_character_range = false;
        }
        if char == '{' {
            in_string_list = true;
        }
        if (char == '/') & in_string_list {
            return Err(OscError::BadAddress("String list (curly brackets) was started but not closed before the next address part started"));
        }
        if char == '}' {
            in_string_list = false;
            if in_character_range {
                return Err(OscError::BadAddress("Can not start a string list (curly brackets) within character range (square brackets)"));
            }
        }
    }
    if in_character_range {
        return Err(OscError::BadAddress("Character range (square brackets) was started but not closed before the end of the address"));
    }
    if in_string_list {
        return Err(OscError::BadAddress("String list (curly brackets) was started but not closed before the end of the address"));
    }

    return Ok(());
}

/// Match a single part of two OSC addresses
fn match_part(message_part: &str, method_part: &str) -> bool
{
    // direct match
    if message_part == method_part {
        return true;
    }

    // Use regex for everything else
    let mut pattern = message_part.to_string()
        .replace("*", "\\w*")
        .replace("?", "\\w")
        .replace("[!", "[^")
        .replace(",", ")|(?:")
        .replace("{", "(?:")
        .replace("}", ")");

    // Anchor the pattern to beginning and end of string
    pattern = format!("^{}$", pattern);

    let re = Regex::new(pattern.as_str()).unwrap();

    re.is_match(method_part)
}

/// Check if a message address matches a method address
pub fn match_address(message_addr: &str, method_addr: &str) -> Result<bool>
{
    match validate_message_address(message_addr) {
        Ok(()) => {},
        Err(e) => return Err(e)
    }
    match validate_method_address(method_addr) {
        Ok(()) => {},
        Err(e) => return Err(e)
    }

    let message_addr_parts: Vec<&str> = message_addr.split('/').collect();
    let method_addr_parts: Vec<&str> = method_addr.split('/').collect();

    if message_addr_parts.len() != method_addr_parts.len() {
        // Both addresses must have the same amount of parts
        return Ok(false);
    }

    for i in 1..message_addr_parts.len() {
        //println!("Parts: '{}' '{}' {}", message_addr_parts[i], method_addr_parts[i], match_part(message_addr_parts[i], method_addr_parts[i]));
        if !match_part(message_addr_parts[i], method_addr_parts[i]) {
            return Ok(false);
        }
    }

    Ok(true)
}<|endoftext|>