<commit_before>#![feature(type_ascription)]
#![feature(proc_macro)]

extern crate rand;
extern crate time;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate byteorder;
#[macro_use]
extern crate log;

#[macro_use(message, storage_value)]
extern crate exonum;
extern crate blockchain_explorer;

pub mod api;
pub mod wallet;

use std::ops::Deref;

use byteorder::{ByteOrder, LittleEndian};

use exonum::messages::{RawMessage, Message, Error as MessageError};
use exonum::crypto::{PublicKey, Hash, hash};
use exonum::storage::{Map, Database, Fork, Error, MerklePatriciaTable, MapTable, MerkleTable, List};
use exonum::blockchain::{Blockchain, View};

use wallet::{Wallet, WalletId};

pub const TX_TRANSFER_ID: u16 = 128;
pub const TX_ISSUE_ID: u16 = 129;
pub const TX_WALLET_ID: u16 = 130;

message! {
    TxTransfer {
        const ID = TX_TRANSFER_ID;
        const SIZE = 80;

        from:        &PublicKey  [00 => 32]
        to:          &PublicKey  [32 => 64]
        amount:      i64         [64 => 72]
        seed:        u64         [72 => 80]
    }
}

message! {
    TxIssue {
        const ID = TX_ISSUE_ID;
        const SIZE = 48;

        wallet:      &PublicKey  [00 => 32]
        amount:      i64         [32 => 40]
        seed:        u64         [40 => 48]
    }
}

message! {
    TxCreateWallet {
        const ID = TX_WALLET_ID;
        const SIZE = 40;

        pub_key:     &PublicKey  [00 => 32]
        name:        &str        [32 => 40]
    }
}

#[derive(PartialEq, Debug, Clone)]
pub enum CurrencyTx {
    Transfer(TxTransfer),
    Issue(TxIssue),
    CreateWallet(TxCreateWallet),
}

impl From<RawMessage> for CurrencyTx {
    fn from(raw: RawMessage) -> Self {
        CurrencyTx::from_raw(raw).unwrap()
    }
}

impl Message for CurrencyTx {
    fn raw(&self) -> &RawMessage {
        match *self {
            CurrencyTx::Transfer(ref msg) => msg.raw(),
            CurrencyTx::Issue(ref msg) => msg.raw(),
            CurrencyTx::CreateWallet(ref msg) => msg.raw(),
        }
    }

    fn from_raw(raw: RawMessage) -> Result<Self, MessageError> {
        Ok(match raw.message_type() {
            TX_TRANSFER_ID => CurrencyTx::Transfer(TxTransfer::from_raw(raw)?),
            TX_ISSUE_ID => CurrencyTx::Issue(TxIssue::from_raw(raw)?),
            TX_WALLET_ID => CurrencyTx::CreateWallet(TxCreateWallet::from_raw(raw)?),
            _ => panic!("Undefined message type"),
        })
    }

    fn hash(&self) -> Hash {
        match *self {
            CurrencyTx::Transfer(ref msg) => msg.hash(),
            CurrencyTx::Issue(ref msg) => msg.hash(),
            CurrencyTx::CreateWallet(ref msg) => msg.hash(),
        }
    }

    fn verify(&self, pub_key: &PublicKey) -> bool {
        match *self {
            CurrencyTx::Transfer(ref msg) => msg.verify(pub_key),
            CurrencyTx::Issue(ref msg) => msg.verify(pub_key),
            CurrencyTx::CreateWallet(ref msg) => msg.verify(pub_key),
        }
    }
}

impl CurrencyTx {
    pub fn pub_key(&self) -> &PublicKey {
        match *self {
            CurrencyTx::Transfer(ref msg) => msg.from(),
            CurrencyTx::Issue(ref msg) => msg.wallet(),
            CurrencyTx::CreateWallet(ref msg) => msg.pub_key(),
        }
    }
}

#[derive(Clone)]
pub struct CurrencyBlockchain<D: Database> {
    pub db: D,
}

pub struct CurrencyView<F: Fork> {
    pub fork: F,
}

impl<F> View<F> for CurrencyView<F>
    where F: Fork
{
    type Transaction = CurrencyTx;

    fn from_fork(fork: F) -> Self {
        CurrencyView { fork: fork }
    }
}

impl<F> Deref for CurrencyView<F>
    where F: Fork
{
    type Target = F;

    fn deref(&self) -> &Self::Target {
        &self.fork
    }
}

impl<D: Database> Deref for CurrencyBlockchain<D> {
    type Target = D;

    fn deref(&self) -> &D {
        &self.db
    }
}

impl<F> CurrencyView<F>
    where F: Fork
{
    pub fn wallets(&self) -> MerkleTable<MapTable<F, [u8], Vec<u8>>, u64, Wallet> {
        MerkleTable::new(MapTable::new(vec![20], &self))
    }

    pub fn wallet_ids(&self) -> MerklePatriciaTable<MapTable<F, [u8], Vec<u8>>, PublicKey, u64> {
        MerklePatriciaTable::new(MapTable::new(vec![21], &self))
    }

    pub fn wallet(&self, pub_key: &PublicKey) -> Result<Option<(WalletId, Wallet)>, Error> {
        if let Some(id) = self.wallet_ids().get(pub_key)? {
            let wallet_pair = self.wallets().get(id)?.map(|wallet| (id, wallet));
            return Ok(wallet_pair);
        }
        Ok(None)
    }

    pub fn wallet_history(&self,
                          id: WalletId)
                          -> MerkleTable<MapTable<F, [u8], Vec<u8>>, u64, Hash> {
        let mut prefix = vec![22; 9];
        LittleEndian::write_u64(&mut prefix[1..], id);
        MerkleTable::new(MapTable::new(prefix, &self))
    }
}

impl<D> Blockchain for CurrencyBlockchain<D>
    where D: Database
{
    type Database = D;
    type Transaction = CurrencyTx;
    type View = CurrencyView<D::Fork>;

    fn verify_tx(tx: &Self::Transaction) -> bool {
        tx.verify(tx.pub_key())
    }

    fn state_hash(view: &Self::View) -> Result<Hash, Error> {
        let wallets = view.wallets();
        let wallet_ids = view.wallet_ids();

        let mut hashes = Vec::new();
        hashes.extend_from_slice(wallets.root_hash()?.as_ref());
        hashes.extend_from_slice(wallet_ids.root_hash()?.as_ref());

        for item in wallets.values()? {
            if let Some((id, _)) = view.wallet(item.pub_key())? {
                let history = view.wallet_history(id);
                hashes.extend_from_slice(history.root_hash()?.as_ref());
            }
        }
        Ok(hash(&hashes))
    }

    fn execute(view: &Self::View, tx: &Self::Transaction) -> Result<(), Error> {
        let tx_hash = tx.hash();
        match *tx {
            CurrencyTx::Transfer(ref msg) => {
                let from = view.wallet(msg.from())?;
                let to = view.wallet(msg.to())?;
                if let (Some(mut from), Some(mut to)) = (from, to) {
                    if from.1.balance() < msg.amount() {
                        return Ok(());
                    }
                    let from_history = view.wallet_history(from.0);
                    let to_history = view.wallet_history(to.0);
                    from_history.append(tx_hash)?;
                    to_history.append(tx_hash)?;

                    from.1.transfer_to(&mut to.1, msg.amount());
                    from.1.set_history_hash(&from_history.root_hash()?);
                    to.1.set_history_hash(&to_history.root_hash()?);

                    view.wallets().set(from.0, from.1)?;
                    view.wallets().set(to.0, to.1)?;
                }
            }
            CurrencyTx::Issue(ref msg) => {
                if let Some((id, mut wallet)) = view.wallet(msg.wallet())? {
                    let history = view.wallet_history(id);
                    history.append(tx_hash)?;

                    let new_amount = wallet.balance() + msg.amount();
                    wallet.set_balance(new_amount);
                    wallet.set_history_hash(&history.root_hash()?);
                    view.wallets().set(id, wallet)?;
                }
            }
            CurrencyTx::CreateWallet(ref msg) => {
                if let Some(_) = view.wallet_ids().get(msg.pub_key())? {
                    return Ok(());
                }

                let id = view.wallets().len()?;
                view.wallet_history(id).append(tx_hash)?;

                let wallet = Wallet::new(msg.pub_key(),
                                         msg.name(),
                                         0,
                                         &view.wallet_history(id).root_hash()?);
                view.wallets().append(wallet)?;
                view.wallet_ids().put(msg.pub_key(), id)?;
            }
        };
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use byteorder::{ByteOrder, LittleEndian};

    use exonum::crypto::gen_keypair;
    use exonum::storage::MemoryDB;
    use exonum::blockchain::Blockchain;
    use exonum::messages::Message;

    use super::{CurrencyTx, CurrencyBlockchain, TxCreateWallet, TxIssue, TxTransfer};

    #[test]
    fn test_tx_create_wallet() {
        let (p, s) = gen_keypair();
        let n = "babd, Юникод еще работает";

        let tx = TxCreateWallet::new(&p, n, &s);
        assert_eq!(tx.pub_key(), &p);
        assert_eq!(tx.name(), n);

        let tx2 = TxCreateWallet::from_raw(tx.raw().clone()).unwrap();
        assert_eq!(tx2.pub_key(), &p);
        assert_eq!(tx2.name(), n);
    }

    #[test]
    fn test_wallet_prefix() {
        let id = 4096;
        let mut prefix = vec![10; 9];
        LittleEndian::write_u64(&mut prefix[1..], id);
        assert_eq!(prefix, vec![10, 0, 16, 0, 0, 0, 0, 0, 0]);
    }

    #[test]
    fn test_wallet_history() {
        let b = CurrencyBlockchain { db: MemoryDB::new() };
        let v = b.view();

        let (p1, s1) = gen_keypair();
        let (p2, s2) = gen_keypair();

        let cw1 = TxCreateWallet::new(&p1, "tx1", &s1);
        let cw2 = TxCreateWallet::new(&p2, "tx2", &s2);
        CurrencyBlockchain::<MemoryDB>::execute(&v, &CurrencyTx::CreateWallet(cw1.clone()))
            .unwrap();
        CurrencyBlockchain::<MemoryDB>::execute(&v, &CurrencyTx::CreateWallet(cw2.clone()))
            .unwrap();
        let w1 = v.wallet(&p1).unwrap().unwrap();
        let w2 = v.wallet(&p2).unwrap().unwrap();

        assert_eq!(w1.0, 0);
        assert_eq!(w2.0, 1);
        assert_eq!(w1.1.name(), "tx1");
        assert_eq!(w1.1.balance(), 0);
        assert_eq!(w2.1.name(), "tx2");
        assert_eq!(w2.1.balance(), 0);
        let rh1 = v.wallet_history(w1.0).root_hash().unwrap();
        let rh2 = v.wallet_history(w2.0).root_hash().unwrap();
        assert_eq!(&rh1, w1.1.history_hash());
        assert_eq!(&rh2, w2.1.history_hash());

        let iw1 = TxIssue::new(&p1, 1000, 1, &s1);
        let iw2 = TxIssue::new(&p2, 100, 2, &s2);
        CurrencyBlockchain::<MemoryDB>::execute(&v, &CurrencyTx::Issue(iw1.clone())).unwrap();
        CurrencyBlockchain::<MemoryDB>::execute(&v, &CurrencyTx::Issue(iw2.clone())).unwrap();
        let w1 = v.wallet(&p1).unwrap().unwrap();
        let w2 = v.wallet(&p2).unwrap().unwrap();

        assert_eq!(w1.1.balance(), 1000);
        assert_eq!(w2.1.balance(), 100);
        let rh1 = v.wallet_history(w1.0).root_hash().unwrap();
        let rh2 = v.wallet_history(w2.0).root_hash().unwrap();
        assert_eq!(&rh1, w1.1.history_hash());
        assert_eq!(&rh2, w2.1.history_hash());

        let tw = TxTransfer::new(&p1, &p2, 400, 3, &s1);
        CurrencyBlockchain::<MemoryDB>::execute(&v, &CurrencyTx::Transfer(tw.clone())).unwrap();
        let w1 = v.wallet(&p1).unwrap().unwrap();
        let w2 = v.wallet(&p2).unwrap().unwrap();

        assert_eq!(w1.1.balance(), 600);
        assert_eq!(w2.1.balance(), 500);
        let rh1 = v.wallet_history(w1.0).root_hash().unwrap();
        let rh2 = v.wallet_history(w2.0).root_hash().unwrap();
        assert_eq!(&rh1, w1.1.history_hash());
        assert_eq!(&rh2, w2.1.history_hash());

        let h1 = v.wallet_history(w1.0).values().unwrap();
        let h2 = v.wallet_history(w2.0).values().unwrap();
        assert_eq!(h1, vec![cw1.hash(), iw1.hash(), tw.hash()]);
        assert_eq!(h2, vec![cw2.hash(), iw2.hash(), tw.hash()]);
    }
}
<commit_msg>Update lib.rs. Fixed a minor bug in state_hash, which greatly affected the performance.<commit_after>#![feature(type_ascription)]
#![feature(proc_macro)]

extern crate rand;
extern crate time;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate byteorder;
#[macro_use]
extern crate log;

#[macro_use(message, storage_value)]
extern crate exonum;
extern crate blockchain_explorer;

pub mod api;
pub mod wallet;

use std::ops::Deref;

use byteorder::{ByteOrder, LittleEndian};

use exonum::messages::{RawMessage, Message, Error as MessageError};
use exonum::crypto::{PublicKey, Hash, hash};
use exonum::storage::{Map, Database, Fork, Error, MerklePatriciaTable, MapTable, MerkleTable, List};
use exonum::blockchain::{Blockchain, View};

use wallet::{Wallet, WalletId};

pub const TX_TRANSFER_ID: u16 = 128;
pub const TX_ISSUE_ID: u16 = 129;
pub const TX_WALLET_ID: u16 = 130;

message! {
    TxTransfer {
        const ID = TX_TRANSFER_ID;
        const SIZE = 80;

        from:        &PublicKey  [00 => 32]
        to:          &PublicKey  [32 => 64]
        amount:      i64         [64 => 72]
        seed:        u64         [72 => 80]
    }
}

message! {
    TxIssue {
        const ID = TX_ISSUE_ID;
        const SIZE = 48;

        wallet:      &PublicKey  [00 => 32]
        amount:      i64         [32 => 40]
        seed:        u64         [40 => 48]
    }
}

message! {
    TxCreateWallet {
        const ID = TX_WALLET_ID;
        const SIZE = 40;

        pub_key:     &PublicKey  [00 => 32]
        name:        &str        [32 => 40]
    }
}

#[derive(PartialEq, Debug, Clone)]
pub enum CurrencyTx {
    Transfer(TxTransfer),
    Issue(TxIssue),
    CreateWallet(TxCreateWallet),
}

impl From<RawMessage> for CurrencyTx {
    fn from(raw: RawMessage) -> Self {
        CurrencyTx::from_raw(raw).unwrap()
    }
}

impl Message for CurrencyTx {
    fn raw(&self) -> &RawMessage {
        match *self {
            CurrencyTx::Transfer(ref msg) => msg.raw(),
            CurrencyTx::Issue(ref msg) => msg.raw(),
            CurrencyTx::CreateWallet(ref msg) => msg.raw(),
        }
    }

    fn from_raw(raw: RawMessage) -> Result<Self, MessageError> {
        Ok(match raw.message_type() {
            TX_TRANSFER_ID => CurrencyTx::Transfer(TxTransfer::from_raw(raw)?),
            TX_ISSUE_ID => CurrencyTx::Issue(TxIssue::from_raw(raw)?),
            TX_WALLET_ID => CurrencyTx::CreateWallet(TxCreateWallet::from_raw(raw)?),
            _ => panic!("Undefined message type"),
        })
    }

    fn hash(&self) -> Hash {
        match *self {
            CurrencyTx::Transfer(ref msg) => msg.hash(),
            CurrencyTx::Issue(ref msg) => msg.hash(),
            CurrencyTx::CreateWallet(ref msg) => msg.hash(),
        }
    }

    fn verify(&self, pub_key: &PublicKey) -> bool {
        match *self {
            CurrencyTx::Transfer(ref msg) => msg.verify(pub_key),
            CurrencyTx::Issue(ref msg) => msg.verify(pub_key),
            CurrencyTx::CreateWallet(ref msg) => msg.verify(pub_key),
        }
    }
}

impl CurrencyTx {
    pub fn pub_key(&self) -> &PublicKey {
        match *self {
            CurrencyTx::Transfer(ref msg) => msg.from(),
            CurrencyTx::Issue(ref msg) => msg.wallet(),
            CurrencyTx::CreateWallet(ref msg) => msg.pub_key(),
        }
    }
}

#[derive(Clone)]
pub struct CurrencyBlockchain<D: Database> {
    pub db: D,
}

pub struct CurrencyView<F: Fork> {
    pub fork: F,
}

impl<F> View<F> for CurrencyView<F>
    where F: Fork
{
    type Transaction = CurrencyTx;

    fn from_fork(fork: F) -> Self {
        CurrencyView { fork: fork }
    }
}

impl<F> Deref for CurrencyView<F>
    where F: Fork
{
    type Target = F;

    fn deref(&self) -> &Self::Target {
        &self.fork
    }
}

impl<D: Database> Deref for CurrencyBlockchain<D> {
    type Target = D;

    fn deref(&self) -> &D {
        &self.db
    }
}

impl<F> CurrencyView<F>
    where F: Fork
{
    pub fn wallets(&self) -> MerkleTable<MapTable<F, [u8], Vec<u8>>, u64, Wallet> {
        MerkleTable::new(MapTable::new(vec![20], &self))
    }

    pub fn wallet_ids(&self) -> MerklePatriciaTable<MapTable<F, [u8], Vec<u8>>, PublicKey, u64> {
        MerklePatriciaTable::new(MapTable::new(vec![21], &self))
    }

    pub fn wallet(&self, pub_key: &PublicKey) -> Result<Option<(WalletId, Wallet)>, Error> {
        if let Some(id) = self.wallet_ids().get(pub_key)? {
            let wallet_pair = self.wallets().get(id)?.map(|wallet| (id, wallet));
            return Ok(wallet_pair);
        }
        Ok(None)
    }

    pub fn wallet_history(&self,
                          id: WalletId)
                          -> MerkleTable<MapTable<F, [u8], Vec<u8>>, u64, Hash> {
        let mut prefix = vec![22; 9];
        LittleEndian::write_u64(&mut prefix[1..], id);
        MerkleTable::new(MapTable::new(prefix, &self))
    }
}

impl<D> Blockchain for CurrencyBlockchain<D>
    where D: Database
{
    type Database = D;
    type Transaction = CurrencyTx;
    type View = CurrencyView<D::Fork>;

    fn verify_tx(tx: &Self::Transaction) -> bool {
        tx.verify(tx.pub_key())
    }

    fn state_hash(view: &Self::View) -> Result<Hash, Error> {
        let wallets = view.wallets();
        let wallet_ids = view.wallet_ids();

        let mut hashes = Vec::new();
        hashes.extend_from_slice(wallets.root_hash()?.as_ref());
        hashes.extend_from_slice(wallet_ids.root_hash()?.as_ref());

        Ok(hash(&hashes))
    }

    fn execute(view: &Self::View, tx: &Self::Transaction) -> Result<(), Error> {
        let tx_hash = tx.hash();
        match *tx {
            CurrencyTx::Transfer(ref msg) => {
                let from = view.wallet(msg.from())?;
                let to = view.wallet(msg.to())?;
                if let (Some(mut from), Some(mut to)) = (from, to) {
                    if from.1.balance() < msg.amount() {
                        return Ok(());
                    }
                    let from_history = view.wallet_history(from.0);
                    let to_history = view.wallet_history(to.0);
                    from_history.append(tx_hash)?;
                    to_history.append(tx_hash)?;

                    from.1.transfer_to(&mut to.1, msg.amount());
                    from.1.set_history_hash(&from_history.root_hash()?);
                    to.1.set_history_hash(&to_history.root_hash()?);

                    view.wallets().set(from.0, from.1)?;
                    view.wallets().set(to.0, to.1)?;
                }
            }
            CurrencyTx::Issue(ref msg) => {
                if let Some((id, mut wallet)) = view.wallet(msg.wallet())? {
                    let history = view.wallet_history(id);
                    history.append(tx_hash)?;

                    let new_amount = wallet.balance() + msg.amount();
                    wallet.set_balance(new_amount);
                    wallet.set_history_hash(&history.root_hash()?);
                    view.wallets().set(id, wallet)?;
                }
            }
            CurrencyTx::CreateWallet(ref msg) => {
                if let Some(_) = view.wallet_ids().get(msg.pub_key())? {
                    return Ok(());
                }

                let id = view.wallets().len()?;
                view.wallet_history(id).append(tx_hash)?;

                let wallet = Wallet::new(msg.pub_key(),
                                         msg.name(),
                                         0,
                                         &view.wallet_history(id).root_hash()?);
                view.wallets().append(wallet)?;
                view.wallet_ids().put(msg.pub_key(), id)?;
            }
        };
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use byteorder::{ByteOrder, LittleEndian};

    use exonum::crypto::gen_keypair;
    use exonum::storage::MemoryDB;
    use exonum::blockchain::Blockchain;
    use exonum::messages::Message;

    use super::{CurrencyTx, CurrencyBlockchain, TxCreateWallet, TxIssue, TxTransfer};

    #[test]
    fn test_tx_create_wallet() {
        let (p, s) = gen_keypair();
        let n = "babd, Юникод еще работает";

        let tx = TxCreateWallet::new(&p, n, &s);
        assert_eq!(tx.pub_key(), &p);
        assert_eq!(tx.name(), n);

        let tx2 = TxCreateWallet::from_raw(tx.raw().clone()).unwrap();
        assert_eq!(tx2.pub_key(), &p);
        assert_eq!(tx2.name(), n);
    }

    #[test]
    fn test_wallet_prefix() {
        let id = 4096;
        let mut prefix = vec![10; 9];
        LittleEndian::write_u64(&mut prefix[1..], id);
        assert_eq!(prefix, vec![10, 0, 16, 0, 0, 0, 0, 0, 0]);
    }

    #[test]
    fn test_wallet_history() {
        let b = CurrencyBlockchain { db: MemoryDB::new() };
        let v = b.view();

        let (p1, s1) = gen_keypair();
        let (p2, s2) = gen_keypair();

        let cw1 = TxCreateWallet::new(&p1, "tx1", &s1);
        let cw2 = TxCreateWallet::new(&p2, "tx2", &s2);
        CurrencyBlockchain::<MemoryDB>::execute(&v, &CurrencyTx::CreateWallet(cw1.clone()))
            .unwrap();
        CurrencyBlockchain::<MemoryDB>::execute(&v, &CurrencyTx::CreateWallet(cw2.clone()))
            .unwrap();
        let w1 = v.wallet(&p1).unwrap().unwrap();
        let w2 = v.wallet(&p2).unwrap().unwrap();

        assert_eq!(w1.0, 0);
        assert_eq!(w2.0, 1);
        assert_eq!(w1.1.name(), "tx1");
        assert_eq!(w1.1.balance(), 0);
        assert_eq!(w2.1.name(), "tx2");
        assert_eq!(w2.1.balance(), 0);
        let rh1 = v.wallet_history(w1.0).root_hash().unwrap();
        let rh2 = v.wallet_history(w2.0).root_hash().unwrap();
        assert_eq!(&rh1, w1.1.history_hash());
        assert_eq!(&rh2, w2.1.history_hash());

        let iw1 = TxIssue::new(&p1, 1000, 1, &s1);
        let iw2 = TxIssue::new(&p2, 100, 2, &s2);
        CurrencyBlockchain::<MemoryDB>::execute(&v, &CurrencyTx::Issue(iw1.clone())).unwrap();
        CurrencyBlockchain::<MemoryDB>::execute(&v, &CurrencyTx::Issue(iw2.clone())).unwrap();
        let w1 = v.wallet(&p1).unwrap().unwrap();
        let w2 = v.wallet(&p2).unwrap().unwrap();

        assert_eq!(w1.1.balance(), 1000);
        assert_eq!(w2.1.balance(), 100);
        let rh1 = v.wallet_history(w1.0).root_hash().unwrap();
        let rh2 = v.wallet_history(w2.0).root_hash().unwrap();
        assert_eq!(&rh1, w1.1.history_hash());
        assert_eq!(&rh2, w2.1.history_hash());

        let tw = TxTransfer::new(&p1, &p2, 400, 3, &s1);
        CurrencyBlockchain::<MemoryDB>::execute(&v, &CurrencyTx::Transfer(tw.clone())).unwrap();
        let w1 = v.wallet(&p1).unwrap().unwrap();
        let w2 = v.wallet(&p2).unwrap().unwrap();

        assert_eq!(w1.1.balance(), 600);
        assert_eq!(w2.1.balance(), 500);
        let rh1 = v.wallet_history(w1.0).root_hash().unwrap();
        let rh2 = v.wallet_history(w2.0).root_hash().unwrap();
        assert_eq!(&rh1, w1.1.history_hash());
        assert_eq!(&rh2, w2.1.history_hash());

        let h1 = v.wallet_history(w1.0).values().unwrap();
        let h2 = v.wallet_history(w2.0).values().unwrap();
        assert_eq!(h1, vec![cw1.hash(), iw1.hash(), tw.hash()]);
        assert_eq!(h2, vec![cw2.hash(), iw2.hash(), tw.hash()]);
    }
}
<|endoftext|>


<commit_before>#![feature(maybe_uninit_extra)]
use std::mem::MaybeUninit;
use std::cell::{Cell, RefCell, UnsafeCell};

fn main() {
    aliasing_mut_and_shr();
    aliasing_frz_and_shr();
    into_interior_mutability();
    unsafe_cell_2phase();
}

fn aliasing_mut_and_shr() {
    fn inner(rc: &RefCell<i32>, aliasing: &mut i32) {
        *aliasing += 4;
        let _escape_to_raw = rc as *const _;
        *aliasing += 4;
        let _shr = &*rc;
        *aliasing += 4;
        // also turning this into a frozen ref now must work
        let aliasing = &*aliasing;
        let _val = *aliasing;
        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
        let _val = *aliasing;
        let _shr = &*rc; // this must NOT unfreeze
        let _val = *aliasing;
    }

    let rc = RefCell::new(23);
    let mut bmut = rc.borrow_mut();
    inner(&rc, &mut *bmut);
    drop(bmut);
    assert_eq!(*rc.borrow(), 23+12);
}

fn aliasing_frz_and_shr() {
    fn inner(rc: &RefCell<i32>, aliasing: &i32) {
        let _val = *aliasing;
        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
        let _val = *aliasing;
        let _shr = &*rc; // this must NOT unfreeze
        let _val = *aliasing;
    }

    let rc = RefCell::new(23);
    let bshr = rc.borrow();
    inner(&rc, &*bshr);
    assert_eq!(*rc.borrow(), 23);
}

// Getting a pointer into a union with interior mutability used to be tricky
// business (https://github.com/rust-lang/miri/issues/615), but it should work
// now.
fn into_interior_mutability() {
    let mut x: MaybeUninit<(Cell<u32>, u32)> = MaybeUninit::uninit();
    x.as_ptr();
    x.write((Cell::new(0), 1));
    let ptr = unsafe { x.assume_init_ref() };
    assert_eq!(ptr.1, 1);
}

// Two-phase borrows of the pointer returned by UnsafeCell::get() should not
// invalidate aliases.
fn unsafe_cell_2phase() { unsafe {
    let x = &UnsafeCell::new(vec![]);
    let x2 = &*x;
    (*x.get()).push(0);
    let _val = (*x2.get()).get(0);
} }
<commit_msg>Auto merge of #1961 - ojeda:spurious-maybe_uninit_extra, r=oli-obk<commit_after>use std::mem::MaybeUninit;
use std::cell::{Cell, RefCell, UnsafeCell};

fn main() {
    aliasing_mut_and_shr();
    aliasing_frz_and_shr();
    into_interior_mutability();
    unsafe_cell_2phase();
}

fn aliasing_mut_and_shr() {
    fn inner(rc: &RefCell<i32>, aliasing: &mut i32) {
        *aliasing += 4;
        let _escape_to_raw = rc as *const _;
        *aliasing += 4;
        let _shr = &*rc;
        *aliasing += 4;
        // also turning this into a frozen ref now must work
        let aliasing = &*aliasing;
        let _val = *aliasing;
        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
        let _val = *aliasing;
        let _shr = &*rc; // this must NOT unfreeze
        let _val = *aliasing;
    }

    let rc = RefCell::new(23);
    let mut bmut = rc.borrow_mut();
    inner(&rc, &mut *bmut);
    drop(bmut);
    assert_eq!(*rc.borrow(), 23+12);
}

fn aliasing_frz_and_shr() {
    fn inner(rc: &RefCell<i32>, aliasing: &i32) {
        let _val = *aliasing;
        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
        let _val = *aliasing;
        let _shr = &*rc; // this must NOT unfreeze
        let _val = *aliasing;
    }

    let rc = RefCell::new(23);
    let bshr = rc.borrow();
    inner(&rc, &*bshr);
    assert_eq!(*rc.borrow(), 23);
}

// Getting a pointer into a union with interior mutability used to be tricky
// business (https://github.com/rust-lang/miri/issues/615), but it should work
// now.
fn into_interior_mutability() {
    let mut x: MaybeUninit<(Cell<u32>, u32)> = MaybeUninit::uninit();
    x.as_ptr();
    x.write((Cell::new(0), 1));
    let ptr = unsafe { x.assume_init_ref() };
    assert_eq!(ptr.1, 1);
}

// Two-phase borrows of the pointer returned by UnsafeCell::get() should not
// invalidate aliases.
fn unsafe_cell_2phase() { unsafe {
    let x = &UnsafeCell::new(vec![]);
    let x2 = &*x;
    (*x.get()).push(0);
    let _val = (*x2.get()).get(0);
} }
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use aptos_indexer::{
    database::{new_db_pool, PgDbPool, PgPoolConnection},
    default_processor::DefaultTransactionProcessor,
    indexer::tailer::Tailer,
    models::transactions::TransactionModel,
};
use diesel::connection::Connection;
use forge::{AptosContext, AptosTest, Result, Test};
use std::sync::Arc;

pub struct Indexer;

impl Test for Indexer {
    fn name(&self) -> &'static str {
        "ecosystem::indexer"
    }
}

pub fn wipe_database(conn: &PgPoolConnection) {
    for table in [
        "write_set_changes",
        "events",
        "user_transactions",
        "block_metadata_transactions",
        "transactions",
        "processor_statuses",
        "__diesel_schema_migrations",
    ] {
        conn.execute(&format!("DROP TABLE IF EXISTS {}", table))
            .unwrap();
    }
}

/// By default, skips test unless `INDEXER_DATABASE_URL` is set.
/// In CI, will explode if `INDEXER_DATABASE_URL` is NOT set.
pub fn should_skip() -> bool {
    if std::env::var("CIRCLECI").is_ok() {
        std::env::var("INDEXER_DATABASE_URL").expect("must set 'INDEXER_DATABASE_URL' in CI!");
    }
    if std::env::var("INDEXER_DATABASE_URL").is_ok() {
        false
    } else {
        println!("`INDEXER_DATABASE_URL` is not set: skipping indexer tests");
        true
    }
}

pub fn setup_indexer(ctx: &mut AptosContext) -> anyhow::Result<(PgDbPool, Tailer)> {
    let database_url = std::env::var("INDEXER_DATABASE_URL")
        .expect("must set 'INDEXER_DATABASE_URL' to run tests!");

    let conn_pool = new_db_pool(database_url.as_str())?;
    wipe_database(&conn_pool.get()?);

    let mut tailer = Tailer::new(ctx.url(), conn_pool.clone())?;
    tailer.run_migrations();

    let pg_transaction_processor = DefaultTransactionProcessor::new(conn_pool.clone());
    tailer.add_processor(Arc::new(pg_transaction_processor));
    Ok((conn_pool, tailer))
}

#[async_trait::async_trait]
impl AptosTest for Indexer {
    async fn run<'t>(&self, ctx: &mut AptosContext<'t>) -> Result<()> {
        if aptos_indexer::should_skip_pg_tests() {
            return Ok(());
        }
        let (conn_pool, mut tailer) = setup_indexer(ctx)?;

        let client = ctx.client();
        client.get_ledger_information().await.unwrap();

        // Set up accounts, generate some traffic
        let mut account1 = ctx.create_and_fund_user_account(1000).await.unwrap();
        let account2 = ctx.create_and_fund_user_account(1000).await.unwrap();
        // This transfer should emit events
        let t_tx = ctx.transfer(&mut account1, &account2, 717).await.unwrap();

        // Why do this twice? To ensure the idempotency of the tailer :-)
        let mut version: u64 = 0;
        for _ in 0..2 {
            // Process the next versions
            version = client
                .get_ledger_information()
                .await
                .unwrap()
                .into_inner()
                .version;

            tailer.process_next_batch((version + 1) as u8).await;

            // This is the genesis transaction
            let (tx0, ut0, bmt0, events0, wsc0) =
                TransactionModel::get_by_version(0, &conn_pool.get()?).unwrap();
            assert_eq!(tx0.type_, "genesis_transaction");
            assert!(ut0.is_none());
            assert!(bmt0.is_none());
            assert_eq!(events0.len(), 1);
            assert_eq!(wsc0.len(), 54);

            // This is a block metadata transaction
            let (tx1, ut1, bmt1, events1, wsc1) =
                TransactionModel::get_by_version(3, &conn_pool.get()?).unwrap();
            assert_eq!(tx1.type_, "block_metadata_transaction");
            assert!(ut1.is_none());
            assert!(bmt1.is_some());
            assert_eq!(events1.len(), 0);
            assert_eq!(wsc1.len(), 2);

            // This is the transfer
            let (tx2, ut2, bmt2, events2, wsc2) =
                TransactionModel::get_by_hash(t_tx.hash.to_string().as_str(), &conn_pool.get()?)
                    .unwrap();

            assert_eq!(tx2.hash, t_tx.hash.to_string());

            // This is a user transaction, so the bmt should be None
            assert!(ut2.is_some());
            assert!(bmt2.is_none());
            assert_eq!(wsc2.len(), 6);

            assert_eq!(events2.len(), 2);
            assert_eq!(events2.get(0).unwrap().type_, "0x1::TestCoin::SentEvent");
            assert_eq!(
                events2.get(1).unwrap().type_,
                "0x1::TestCoin::ReceivedEvent"
            );
        }

        let latest_version = tailer.set_fetcher_to_lowest_processor_version().await;
        assert!(latest_version > version);

        Ok(())
    }
}
<commit_msg>[ecosystem][indexer] Fix a flakey test<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use aptos_indexer::{
    database::{new_db_pool, PgDbPool, PgPoolConnection},
    default_processor::DefaultTransactionProcessor,
    indexer::tailer::Tailer,
    models::transactions::TransactionModel,
};
use diesel::connection::Connection;
use forge::{AptosContext, AptosTest, Result, Test};
use std::sync::Arc;

pub struct Indexer;

impl Test for Indexer {
    fn name(&self) -> &'static str {
        "ecosystem::indexer"
    }
}

pub fn wipe_database(conn: &PgPoolConnection) {
    for table in [
        "write_set_changes",
        "events",
        "user_transactions",
        "block_metadata_transactions",
        "transactions",
        "processor_statuses",
        "__diesel_schema_migrations",
    ] {
        conn.execute(&format!("DROP TABLE IF EXISTS {}", table))
            .unwrap();
    }
}

/// By default, skips test unless `INDEXER_DATABASE_URL` is set.
/// In CI, will explode if `INDEXER_DATABASE_URL` is NOT set.
pub fn should_skip() -> bool {
    if std::env::var("CIRCLECI").is_ok() {
        std::env::var("INDEXER_DATABASE_URL").expect("must set 'INDEXER_DATABASE_URL' in CI!");
    }
    if std::env::var("INDEXER_DATABASE_URL").is_ok() {
        false
    } else {
        println!("`INDEXER_DATABASE_URL` is not set: skipping indexer tests");
        true
    }
}

pub fn setup_indexer(ctx: &mut AptosContext) -> anyhow::Result<(PgDbPool, Tailer)> {
    let database_url = std::env::var("INDEXER_DATABASE_URL")
        .expect("must set 'INDEXER_DATABASE_URL' to run tests!");

    let conn_pool = new_db_pool(database_url.as_str())?;
    wipe_database(&conn_pool.get()?);

    let mut tailer = Tailer::new(ctx.url(), conn_pool.clone())?;
    tailer.run_migrations();

    let pg_transaction_processor = DefaultTransactionProcessor::new(conn_pool.clone());
    tailer.add_processor(Arc::new(pg_transaction_processor));
    Ok((conn_pool, tailer))
}

#[async_trait::async_trait]
impl AptosTest for Indexer {
    async fn run<'t>(&self, ctx: &mut AptosContext<'t>) -> Result<()> {
        if aptos_indexer::should_skip_pg_tests() {
            return Ok(());
        }
        let (conn_pool, mut tailer) = setup_indexer(ctx)?;

        let client = ctx.client();
        client.get_ledger_information().await.unwrap();

        // Set up accounts, generate some traffic
        let mut account1 = ctx.create_and_fund_user_account(1000).await.unwrap();
        let account2 = ctx.create_and_fund_user_account(1000).await.unwrap();
        // This transfer should emit events
        let t_tx = ctx.transfer(&mut account1, &account2, 717).await.unwrap();

        // Why do this twice? To ensure the idempotency of the tailer :-)
        let mut version: u64 = 0;
        for _ in 0..2 {
            // Process the next versions
            version = client
                .get_ledger_information()
                .await
                .unwrap()
                .into_inner()
                .version;

            tailer.process_next_batch((version + 1) as u8).await;

            // Get them into the array and sort by type in order to prevent ordering from breaking tests
            let mut transactions = vec![];
            for v in 0..2 {
                transactions.push(TransactionModel::get_by_version(v, &conn_pool.get()?).unwrap());
            }
            transactions.sort_by(|a, b| a.0.type_.partial_cmp(&b.0.type_).unwrap());

            // This is a block metadata transaction
            let (tx1, ut1, bmt1, events1, wsc1) = &transactions[0];
            assert_eq!(tx1.type_, "block_metadata_transaction");
            assert!(ut1.is_none());
            assert!(bmt1.is_some());
            assert!(events1.is_empty());
            assert!(!wsc1.is_empty());

            // This is the genesis transaction
            let (tx0, ut0, bmt0, events0, wsc0) = &transactions[1];
            assert_eq!(tx0.type_, "genesis_transaction");
            assert!(ut0.is_none());
            assert!(bmt0.is_none());
            assert!(!events0.is_empty());
            assert!(wsc0.len() > 10);

            // This is the transfer
            let (tx2, ut2, bmt2, events2, wsc2) =
                TransactionModel::get_by_hash(t_tx.hash.to_string().as_str(), &conn_pool.get()?)
                    .unwrap();

            assert_eq!(tx2.type_, "user_transaction");
            assert_eq!(tx2.hash, t_tx.hash.to_string());

            // This is a user transaction, so the bmt should be None
            assert!(ut2.is_some());
            assert!(bmt2.is_none());
            assert!(wsc2.len() > 1);
            assert_eq!(events2.len(), 2);
            assert_eq!(events2.get(0).unwrap().type_, "0x1::TestCoin::SentEvent");
            assert_eq!(
                events2.get(1).unwrap().type_,
                "0x1::TestCoin::ReceivedEvent"
            );
        }

        let latest_version = tailer.set_fetcher_to_lowest_processor_version().await;
        assert!(latest_version > version);

        Ok(())
    }
}
<|endoftext|>


<commit_before>#![allow(missing_copy_implementations)]

#[cfg(test)]
mod tests;

use crate::fmt;
use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write};

/// A reader which is always at EOF.
///
/// This struct is generally created by calling [`empty()`]. Please see
/// the documentation of [`empty()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Empty {
    _priv: (),
}

/// Constructs a new handle to an empty reader.
///
/// All reads from the returned reader will return [`Ok`]`(0)`.
///
/// # Examples
///
/// A slightly sad example of not reading anything into a buffer:
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = String::new();
/// io::empty().read_to_string(&mut buffer).unwrap();
/// assert!(buffer.is_empty());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn empty() -> Empty {
    Empty { _priv: () }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Empty {
    #[inline]
    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
        Ok(0)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl BufRead for Empty {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        Ok(&[])
    }
    #[inline]
    fn consume(&mut self, _n: usize) {}
}

#[stable(feature = "empty_seek", since = "1.51.0")]
impl Seek for Empty {
    fn seek(&mut self, _pos: SeekFrom) -> io::Result<u64> {
        Ok(0)
    }

    fn stream_len(&mut self) -> io::Result<u64> {
        Ok(0)
    }

    fn stream_position(&mut self) -> io::Result<u64> {
        Ok(0)
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Empty {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("Empty { .. }")
    }
}

impl SizeHint for Empty {
    fn upper_bound(&self) -> Option<usize> {
        Some(0)
    }
}

/// A reader which yields one byte over and over and over and over and over and...
///
/// This struct is generally created by calling [`repeat()`]. Please
/// see the documentation of [`repeat()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Repeat {
    byte: u8,
}

/// Creates an instance of a reader that infinitely repeats one byte.
///
/// All reads from this reader will succeed by filling the specified buffer with
/// the given byte.
///
/// # Examples
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = [0; 3];
/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn repeat(byte: u8) -> Repeat {
    Repeat { byte }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Repeat {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        for slot in &mut *buf {
            *slot = self.byte;
        }
        Ok(buf.len())
    }

    #[inline]
    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        let mut nwritten = 0;
        for buf in bufs {
            nwritten += self.read(buf)?;
        }
        Ok(nwritten)
    }

    #[inline]
    fn is_read_vectored(&self) -> bool {
        true
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Repeat {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("Repeat { .. }")
    }
}

/// A writer which will move data into the void.
///
/// This struct is generally created by calling [`sink`]. Please
/// see the documentation of [`sink()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Sink {
    _priv: (),
}

/// Creates an instance of a writer which will successfully consume all data.
///
/// All calls to [`write`] on the returned instance will return `Ok(buf.len())`
/// and the contents of the buffer will not be inspected.
///
/// [`write`]: Write::write
///
/// # Examples
///
/// ```rust
/// use std::io::{self, Write};
///
/// let buffer = vec![1, 2, 3, 5, 8];
/// let num_bytes = io::sink().write(&buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn sink() -> Sink {
    Sink { _priv: () }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Sink {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        Ok(buf.len())
    }

    #[inline]
    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let total_len = bufs.iter().map(|b| b.len()).sum();
        Ok(total_len)
    }

    #[inline]
    fn is_write_vectored(&self) -> bool {
        true
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[stable(feature = "write_mt", since = "1.48.0")]
impl Write for &Sink {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        Ok(buf.len())
    }

    #[inline]
    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let total_len = bufs.iter().map(|b| b.len()).sum();
        Ok(total_len)
    }

    #[inline]
    fn is_write_vectored(&self) -> bool {
        true
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Sink {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("Sink { .. }")
    }
}
<commit_msg>Fix line length format<commit_after>#![allow(missing_copy_implementations)]

#[cfg(test)]
mod tests;

use crate::fmt;
use crate::io::{
    self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
};

/// A reader which is always at EOF.
///
/// This struct is generally created by calling [`empty()`]. Please see
/// the documentation of [`empty()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Empty {
    _priv: (),
}

/// Constructs a new handle to an empty reader.
///
/// All reads from the returned reader will return [`Ok`]`(0)`.
///
/// # Examples
///
/// A slightly sad example of not reading anything into a buffer:
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = String::new();
/// io::empty().read_to_string(&mut buffer).unwrap();
/// assert!(buffer.is_empty());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn empty() -> Empty {
    Empty { _priv: () }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Empty {
    #[inline]
    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
        Ok(0)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl BufRead for Empty {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        Ok(&[])
    }
    #[inline]
    fn consume(&mut self, _n: usize) {}
}

#[stable(feature = "empty_seek", since = "1.51.0")]
impl Seek for Empty {
    fn seek(&mut self, _pos: SeekFrom) -> io::Result<u64> {
        Ok(0)
    }

    fn stream_len(&mut self) -> io::Result<u64> {
        Ok(0)
    }

    fn stream_position(&mut self) -> io::Result<u64> {
        Ok(0)
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Empty {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("Empty { .. }")
    }
}

impl SizeHint for Empty {
    fn upper_bound(&self) -> Option<usize> {
        Some(0)
    }
}

/// A reader which yields one byte over and over and over and over and over and...
///
/// This struct is generally created by calling [`repeat()`]. Please
/// see the documentation of [`repeat()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Repeat {
    byte: u8,
}

/// Creates an instance of a reader that infinitely repeats one byte.
///
/// All reads from this reader will succeed by filling the specified buffer with
/// the given byte.
///
/// # Examples
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = [0; 3];
/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn repeat(byte: u8) -> Repeat {
    Repeat { byte }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Repeat {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        for slot in &mut *buf {
            *slot = self.byte;
        }
        Ok(buf.len())
    }

    #[inline]
    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        let mut nwritten = 0;
        for buf in bufs {
            nwritten += self.read(buf)?;
        }
        Ok(nwritten)
    }

    #[inline]
    fn is_read_vectored(&self) -> bool {
        true
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Repeat {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("Repeat { .. }")
    }
}

/// A writer which will move data into the void.
///
/// This struct is generally created by calling [`sink`]. Please
/// see the documentation of [`sink()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Sink {
    _priv: (),
}

/// Creates an instance of a writer which will successfully consume all data.
///
/// All calls to [`write`] on the returned instance will return `Ok(buf.len())`
/// and the contents of the buffer will not be inspected.
///
/// [`write`]: Write::write
///
/// # Examples
///
/// ```rust
/// use std::io::{self, Write};
///
/// let buffer = vec![1, 2, 3, 5, 8];
/// let num_bytes = io::sink().write(&buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn sink() -> Sink {
    Sink { _priv: () }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Sink {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        Ok(buf.len())
    }

    #[inline]
    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let total_len = bufs.iter().map(|b| b.len()).sum();
        Ok(total_len)
    }

    #[inline]
    fn is_write_vectored(&self) -> bool {
        true
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[stable(feature = "write_mt", since = "1.48.0")]
impl Write for &Sink {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        Ok(buf.len())
    }

    #[inline]
    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let total_len = bufs.iter().map(|b| b.len()).sum();
        Ok(total_len)
    }

    #[inline]
    fn is_write_vectored(&self) -> bool {
        true
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Sink {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("Sink { .. }")
    }
}
<|endoftext|>


<commit_before>/*
 * An example redis server accepting GET and SET requests
 * listening on 127.0.0.1:8000.
 *
 * You can test it with "redis-cli -p 8000".
 *
 * Copyright (c) 2014 by Michael Neumann
 *
 */

extern crate redis = "redis#0.1";
extern crate sync = "sync#0.10-pre";

use std::io::net::ip::SocketAddr;
use std::io::net::tcp::{TcpListener,TcpStream};
use std::io::{Listener,Acceptor,Writer};
use std::io::BufferedStream;
use std::task;
use std::hashmap::HashMap;
use sync::RWArc;

fn handle_connection(conn: TcpStream, shared_ht: RWArc<HashMap<~[u8],~[u8]>>) {
    debug!("Got connection");

    let mut io = BufferedStream::new(conn);

    loop {
        match redis::parse(&mut io).unwrap() {
            redis::List(ref lst) => {
                match lst.get(0) {
                    Some(&redis::Data(ref command)) => {
                        if command.as_slice() == bytes!("GET") {
                            match (lst.len(), lst.get(1)) {
                                (2, Some(&redis::Data(ref key))) => {
                                    debug!("GET: {:s}", std::str::from_utf8(key.as_slice()).unwrap());
                                    let mut cwr = redis::CommandWriter::new();
                                    shared_ht.read(|ht| {
                                        match ht.find(key) {
                                            Some(val) => {
                                                cwr.args(1);
                                                cwr.arg_bin(*val);
                                            }
                                            None => {
                                                cwr.nil();
                                            }
                                        }
                                    });
                                    cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
                                    continue;
                                }
                                _ => { /* fallthrough: error */ }
                            }
                        }
                        else if command.as_slice() == bytes!("SET") {
                            match (lst.len(), lst.get(1), lst.get(2)) {
                                (3, Some(&redis::Data(ref key)), Some(&redis::Data(ref val))) => {
                                    debug!("SET: {:s} {:?}", std::str::from_utf8(key.as_slice()).unwrap(), val);
                                    shared_ht.write(|ht| ht.insert(key.clone(), val.clone()));
                                    let mut cwr = redis::CommandWriter::new();
                                    cwr.status("OK");
                                    cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
                                    continue;
                                }
                                _ => { /* fallthrough: error */ }
                            }
                        }
                        else {
                            /* fallthrough: error */
                        }
                    }
                    _ => { /* fallthrough: error */ }
                }
            }
            _ => { /* fallthrough: error */ }
        }

        /* error */
        let mut cwr = redis::CommandWriter::new();
        cwr.error("Invalid Command");
        cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
    }
}

fn main() {
    let addr: SocketAddr = from_str("127.0.0.1:8000").unwrap();
    let shared_ht = RWArc::new(HashMap::new());

    match TcpListener::bind(addr) {
        Ok(listener) => {
            match listener.listen() {
                Ok(ref mut acceptor) => {
                    loop {
                        match acceptor.accept() {
                            Ok(conn) => {
                                let ht = shared_ht.clone();
                                task::spawn(proc() {
                                    handle_connection(conn, ht)
                                });
                            }
                            Err(_) => {}
                        }
                    }
                }
                Err(_) => {}
            }
        }
        Err(_) => {}
    }
}
<commit_msg>HashMap moved into libcollections<commit_after>/*
 * An example redis server accepting GET and SET requests
 * listening on 127.0.0.1:8000.
 *
 * You can test it with "redis-cli -p 8000".
 *
 * Copyright (c) 2014 by Michael Neumann
 *
 */

extern crate redis = "redis#0.1";
extern crate sync = "sync#0.10-pre";
extern crate collections;

use std::io::net::ip::SocketAddr;
use std::io::net::tcp::{TcpListener,TcpStream};
use std::io::{Listener,Acceptor,Writer};
use std::io::BufferedStream;
use std::task;
use collections::hashmap::HashMap;
use sync::RWArc;

fn handle_connection(conn: TcpStream, shared_ht: RWArc<HashMap<~[u8],~[u8]>>) {
    debug!("Got connection");

    let mut io = BufferedStream::new(conn);

    loop {
        match redis::parse(&mut io).unwrap() {
            redis::List(ref lst) => {
                match lst.get(0) {
                    Some(&redis::Data(ref command)) => {
                        if command.as_slice() == bytes!("GET") {
                            match (lst.len(), lst.get(1)) {
                                (2, Some(&redis::Data(ref key))) => {
                                    debug!("GET: {:s}", std::str::from_utf8(key.as_slice()).unwrap());
                                    let mut cwr = redis::CommandWriter::new();
                                    shared_ht.read(|ht| {
                                        match ht.find(key) {
                                            Some(val) => {
                                                cwr.args(1);
                                                cwr.arg_bin(*val);
                                            }
                                            None => {
                                                cwr.nil();
                                            }
                                        }
                                    });
                                    cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
                                    continue;
                                }
                                _ => { /* fallthrough: error */ }
                            }
                        }
                        else if command.as_slice() == bytes!("SET") {
                            match (lst.len(), lst.get(1), lst.get(2)) {
                                (3, Some(&redis::Data(ref key)), Some(&redis::Data(ref val))) => {
                                    debug!("SET: {:s} {:?}", std::str::from_utf8(key.as_slice()).unwrap(), val);
                                    shared_ht.write(|ht| ht.insert(key.clone(), val.clone()));
                                    let mut cwr = redis::CommandWriter::new();
                                    cwr.status("OK");
                                    cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
                                    continue;
                                }
                                _ => { /* fallthrough: error */ }
                            }
                        }
                        else {
                            /* fallthrough: error */
                        }
                    }
                    _ => { /* fallthrough: error */ }
                }
            }
            _ => { /* fallthrough: error */ }
        }

        /* error */
        let mut cwr = redis::CommandWriter::new();
        cwr.error("Invalid Command");
        cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
    }
}

fn main() {
    let addr: SocketAddr = from_str("127.0.0.1:8000").unwrap();
    let shared_ht = RWArc::new(HashMap::new());

    match TcpListener::bind(addr) {
        Ok(listener) => {
            match listener.listen() {
                Ok(ref mut acceptor) => {
                    loop {
                        match acceptor.accept() {
                            Ok(conn) => {
                                let ht = shared_ht.clone();
                                task::spawn(proc() {
                                    handle_connection(conn, ht)
                                });
                            }
                            Err(_) => {}
                        }
                    }
                }
                Err(_) => {}
            }
        }
        Err(_) => {}
    }
}
<|endoftext|>


<commit_before>use cgmath;
use cgmath::{Point3, EuclideanSpace};
use gl;
use std;
use std::f32;
use yaglw;
use yaglw::gl_context::GLContext;

use common::entity_id;
use common::fnv_map;

use terrain_mesh;
use vertex;

// VRAM bytes
pub const BYTE_BUDGET: usize = 64_000_000;
pub const TUFT_COST: usize = 8;
pub const TUFT_BUDGET: usize = BYTE_BUDGET / TUFT_COST;

#[derive(Debug, Clone)]
#[repr(C)]
pub struct Entry {
  pub polygon_idx : u32,
  pub tex_id      : u32,
}

/// Struct for loading/unloading/maintaining terrain data in VRAM.
pub struct T<'a> {
  id_to_index: fnv_map::T<entity_id::T, usize>,
  index_to_id: Vec<entity_id::T>,

  to_polygon_id: fnv_map::T<entity_id::T, entity_id::T>,
  of_polygon_id: fnv_map::T<entity_id::T, entity_id::T>,

  gl_array: yaglw::vertex_buffer::ArrayHandle<'a>,
  _instance_vertices: yaglw::vertex_buffer::GLBuffer<'a, vertex::TextureVertex>,
  per_tuft: yaglw::vertex_buffer::GLBuffer<'a, Entry>,
}

#[allow(missing_docs)]
pub fn new<'a, 'b:'a>(
  gl: &'a mut GLContext,
  shader: &yaglw::shader::Shader<'a>,
) -> T<'b>
{
  use yaglw::vertex_buffer;

  let gl_array = vertex_buffer::ArrayHandle::new(gl);
  let mut instance_vertices = vertex_buffer::GLBuffer::new(gl, 18);
  let per_tuft = vertex_buffer::GLBuffer::new(gl, TUFT_BUDGET);

  let mut vertices = Vec::new();
  {
    let tangent = cgmath::Vector3::new(0.0, 0.0, 0.5);
    let normal = cgmath::Vector3::new(0.0, 1.0, 0.0);
    let mut quad = |v: &cgmath::Vector3<f32>| {
      let mut tri = |p0, t0, p1, t1, p2, t2| {
        let vert = |p, t| {
          vertex::TextureVertex {
            world_position: p,
            texture_position: t,
          }
        };
        vertices.push(vert(p0, t0));
        vertices.push(vert(p1, t1));
        vertices.push(vert(p2, t2));
      };

      tri(
        Point3::from_vec(-(*v / 2.0))          , cgmath::Vector2::new(0.0 , 0.0) ,
        Point3::from_vec( (*v / 2.0))          , cgmath::Vector2::new(1.0 , 0.0) ,
        Point3::from_vec( (*v / 2.0 + normal)) , cgmath::Vector2::new(1.0 , 1.0) ,
      );
      tri(
        Point3::from_vec(-(*v / 2.0))          , cgmath::Vector2::new(0.0 , 0.0) ,
        Point3::from_vec( (*v / 2.0 + normal)) , cgmath::Vector2::new(1.0 , 1.0) ,
        Point3::from_vec(-(*v / 2.0 + normal)) , cgmath::Vector2::new(0.0 , 1.0) ,
      );
    };

    quad(&tangent);
    quad(&(cgmath::Matrix3::from_axis_angle(normal, cgmath::rad(f32::consts::FRAC_PI_3)) * tangent));
    quad(&(cgmath::Matrix3::from_axis_angle(normal, cgmath::rad(2.0 * f32::consts::FRAC_PI_3)) * tangent));
  }

  unsafe {
    gl::BindVertexArray(gl_array.gl_id);
  }
  shader.use_shader(gl);
  instance_vertices.byte_buffer.bind(gl);
  instance_vertices.push(gl, &vertices);
  let attrib_span =
    vertex_buffer::VertexAttribData::apply(
      &[
        vertex_buffer::VertexAttribData {
          name: "vertex_position",
          size: 3,
          unit: vertex_buffer::GLType::Float,
          divisor: 0,
        },
        vertex_buffer::VertexAttribData {
          name: "texture_position",
          size: 2,
          unit: vertex_buffer::GLType::Float,
          divisor: 0,
        },
      ],
      gl,
      shader,
    );
  assert!(attrib_span == std::mem::size_of::<vertex::TextureVertex>() as u32);

  per_tuft.byte_buffer.bind(gl);
  let attrib_span =
    vertex_buffer::VertexAttribData::apply(
      &[
        vertex_buffer::VertexAttribData {
          name: "polygon_id",
          size: 1,
          unit: vertex_buffer::GLType::Int,
          divisor: 1,
        },
        vertex_buffer::VertexAttribData {
          name: "tex_id",
          size: 1,
          unit: vertex_buffer::GLType::UInt,
          divisor: 1,
        },
      ],
      gl,
      shader,
    );
  assert!(attrib_span == std::mem::size_of::<terrain_mesh::Grass>() as u32);

  T {
    id_to_index: fnv_map::new(),
    index_to_id: Vec::new(),

    to_polygon_id: fnv_map::new(),
    of_polygon_id: fnv_map::new(),

    gl_array: gl_array,
    _instance_vertices: instance_vertices,
    per_tuft: per_tuft,
  }
}

impl<'a> T<'a> {
  /// Add a series of entites into VRAM.
  pub fn push(
    &mut self,
    gl: &mut GLContext,
    grass: &[Entry],
    polygon_ids: &[entity_id::T],
    grass_ids: &[entity_id::T],
  ) {
    assert!(grass.len() == polygon_ids.len());
    assert!(grass.len() == grass_ids.len());

    self.per_tuft.byte_buffer.bind(gl);
    let success: bool = self.per_tuft.push(gl, grass);
    if !success {
      panic!("Ran out of VRAM for grass");
    }

    for id in grass_ids {
      self.id_to_index.insert(*id, self.index_to_id.len());
      self.index_to_id.push(*id);
    }

    for (id, polygon_id) in grass_ids.iter().zip(polygon_ids.iter()) {
      self.to_polygon_id.insert(*id, *polygon_id);
      self.of_polygon_id.insert(*polygon_id, *id);
    }
  }

  // TODO: Make this take many ids as a parameter, to reduce `bind`s.
  // Note: `id` must be present in the buffers.
  /// Remove some entity from VRAM.
  pub fn swap_remove(&mut self, gl: &mut GLContext, id: entity_id::T) {
    let idx = *self.id_to_index.get(&id).unwrap();
    let swapped_id = self.index_to_id[self.index_to_id.len() - 1];
    self.index_to_id.swap_remove(idx);
    self.id_to_index.remove(&id);

    if id != swapped_id {
      self.id_to_index.insert(swapped_id, idx);
    }

    self.per_tuft.byte_buffer.bind(gl);
    self.per_tuft.swap_remove(gl, idx, 1);

    let polygon_id = self.to_polygon_id.remove(&id).unwrap();
    self.of_polygon_id.remove(&polygon_id).unwrap();
  }

  pub fn update_polygon_index(
    &self,
    gl: &mut GLContext,
    polygon_id: entity_id::T,
    new_index: u32,
  ) {
    let grass_id = self.of_polygon_id.get(&polygon_id).unwrap();
    let entry_idx = self.id_to_index.get(&grass_id).unwrap();
    // update the underlying byte buffer directly and only touch the polygon
    // index field.
    self.per_tuft.byte_buffer.bind(gl);
    unsafe {
      self.per_tuft.byte_buffer.update(
        gl,
        std::mem::size_of::<Entry>() * entry_idx + std::mem::size_of::<u32>(),
        &new_index as *const u32 as *const u8,
        std::mem::size_of::<u32>(),
      );
    }
  }

  pub fn draw(&self, _gl: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.gl_array.gl_id);
      gl::DrawArraysInstanced(gl::TRIANGLES, 0, 18, self.index_to_id.len() as i32);
    }
  }
}
<commit_msg>fix grass updating<commit_after>use cgmath;
use cgmath::{Point3, EuclideanSpace};
use gl;
use std;
use std::f32;
use yaglw;
use yaglw::gl_context::GLContext;

use common::entity_id;
use common::fnv_map;

use terrain_mesh;
use vertex;

// VRAM bytes
pub const BYTE_BUDGET: usize = 64_000_000;
pub const TUFT_COST: usize = 8;
pub const TUFT_BUDGET: usize = BYTE_BUDGET / TUFT_COST;

#[derive(Debug, Clone)]
#[repr(C)]
pub struct Entry {
  pub polygon_idx : u32,
  pub tex_id      : u32,
}

/// Struct for loading/unloading/maintaining terrain data in VRAM.
pub struct T<'a> {
  id_to_index: fnv_map::T<entity_id::T, usize>,
  index_to_id: Vec<entity_id::T>,

  to_polygon_id: fnv_map::T<entity_id::T, entity_id::T>,
  of_polygon_id: fnv_map::T<entity_id::T, entity_id::T>,

  gl_array: yaglw::vertex_buffer::ArrayHandle<'a>,
  _instance_vertices: yaglw::vertex_buffer::GLBuffer<'a, vertex::TextureVertex>,
  per_tuft: yaglw::vertex_buffer::GLBuffer<'a, Entry>,
}

#[allow(missing_docs)]
pub fn new<'a, 'b:'a>(
  gl: &'a mut GLContext,
  shader: &yaglw::shader::Shader<'a>,
) -> T<'b>
{
  use yaglw::vertex_buffer;

  let gl_array = vertex_buffer::ArrayHandle::new(gl);
  let mut instance_vertices = vertex_buffer::GLBuffer::new(gl, 18);
  let per_tuft = vertex_buffer::GLBuffer::new(gl, TUFT_BUDGET);

  let mut vertices = Vec::new();
  {
    let tangent = cgmath::Vector3::new(0.0, 0.0, 0.5);
    let normal = cgmath::Vector3::new(0.0, 1.0, 0.0);
    let mut quad = |v: &cgmath::Vector3<f32>| {
      let mut tri = |p0, t0, p1, t1, p2, t2| {
        let vert = |p, t| {
          vertex::TextureVertex {
            world_position: p,
            texture_position: t,
          }
        };
        vertices.push(vert(p0, t0));
        vertices.push(vert(p1, t1));
        vertices.push(vert(p2, t2));
      };

      tri(
        Point3::from_vec(-(*v / 2.0))          , cgmath::Vector2::new(0.0 , 0.0) ,
        Point3::from_vec( (*v / 2.0))          , cgmath::Vector2::new(1.0 , 0.0) ,
        Point3::from_vec( (*v / 2.0 + normal)) , cgmath::Vector2::new(1.0 , 1.0) ,
      );
      tri(
        Point3::from_vec(-(*v / 2.0))          , cgmath::Vector2::new(0.0 , 0.0) ,
        Point3::from_vec( (*v / 2.0 + normal)) , cgmath::Vector2::new(1.0 , 1.0) ,
        Point3::from_vec(-(*v / 2.0 + normal)) , cgmath::Vector2::new(0.0 , 1.0) ,
      );
    };

    quad(&tangent);
    quad(&(cgmath::Matrix3::from_axis_angle(normal, cgmath::rad(f32::consts::FRAC_PI_3)) * tangent));
    quad(&(cgmath::Matrix3::from_axis_angle(normal, cgmath::rad(2.0 * f32::consts::FRAC_PI_3)) * tangent));
  }

  unsafe {
    gl::BindVertexArray(gl_array.gl_id);
  }
  shader.use_shader(gl);
  instance_vertices.byte_buffer.bind(gl);
  instance_vertices.push(gl, &vertices);
  let attrib_span =
    vertex_buffer::VertexAttribData::apply(
      &[
        vertex_buffer::VertexAttribData {
          name: "vertex_position",
          size: 3,
          unit: vertex_buffer::GLType::Float,
          divisor: 0,
        },
        vertex_buffer::VertexAttribData {
          name: "texture_position",
          size: 2,
          unit: vertex_buffer::GLType::Float,
          divisor: 0,
        },
      ],
      gl,
      shader,
    );
  assert!(attrib_span == std::mem::size_of::<vertex::TextureVertex>() as u32);

  per_tuft.byte_buffer.bind(gl);
  let attrib_span =
    vertex_buffer::VertexAttribData::apply(
      &[
        vertex_buffer::VertexAttribData {
          name: "polygon_id",
          size: 1,
          unit: vertex_buffer::GLType::Int,
          divisor: 1,
        },
        vertex_buffer::VertexAttribData {
          name: "tex_id",
          size: 1,
          unit: vertex_buffer::GLType::UInt,
          divisor: 1,
        },
      ],
      gl,
      shader,
    );
  assert!(attrib_span == std::mem::size_of::<terrain_mesh::Grass>() as u32);

  T {
    id_to_index: fnv_map::new(),
    index_to_id: Vec::new(),

    to_polygon_id: fnv_map::new(),
    of_polygon_id: fnv_map::new(),

    gl_array: gl_array,
    _instance_vertices: instance_vertices,
    per_tuft: per_tuft,
  }
}

impl<'a> T<'a> {
  /// Add a series of entites into VRAM.
  pub fn push(
    &mut self,
    gl: &mut GLContext,
    grass: &[Entry],
    polygon_ids: &[entity_id::T],
    grass_ids: &[entity_id::T],
  ) {
    assert!(grass.len() == polygon_ids.len());
    assert!(grass.len() == grass_ids.len());

    self.per_tuft.byte_buffer.bind(gl);
    let success: bool = self.per_tuft.push(gl, grass);
    if !success {
      panic!("Ran out of VRAM for grass");
    }

    for id in grass_ids {
      self.id_to_index.insert(*id, self.index_to_id.len());
      self.index_to_id.push(*id);
    }

    for (id, polygon_id) in grass_ids.iter().zip(polygon_ids.iter()) {
      self.to_polygon_id.insert(*id, *polygon_id);
      self.of_polygon_id.insert(*polygon_id, *id);
    }
  }

  // TODO: Make this take many ids as a parameter, to reduce `bind`s.
  // Note: `id` must be present in the buffers.
  /// Remove some entity from VRAM.
  pub fn swap_remove(&mut self, gl: &mut GLContext, id: entity_id::T) {
    let idx = *self.id_to_index.get(&id).unwrap();
    let swapped_id = self.index_to_id[self.index_to_id.len() - 1];
    self.index_to_id.swap_remove(idx);
    self.id_to_index.remove(&id);

    if id != swapped_id {
      self.id_to_index.insert(swapped_id, idx);
    }

    self.per_tuft.byte_buffer.bind(gl);
    self.per_tuft.swap_remove(gl, idx, 1);

    let polygon_id = self.to_polygon_id.remove(&id).unwrap();
    self.of_polygon_id.remove(&polygon_id).unwrap();
  }

  pub fn update_polygon_index(
    &self,
    gl: &mut GLContext,
    polygon_id: entity_id::T,
    new_index: u32,
  ) {
    let grass_id =
      match self.of_polygon_id.get(&polygon_id) {
        None => return,
        Some(id) => id,
      };
    let entry_idx = self.id_to_index.get(&grass_id).unwrap();
    // update the underlying byte buffer directly and only touch the polygon
    // index field.
    self.per_tuft.byte_buffer.bind(gl);
    unsafe {
      self.per_tuft.byte_buffer.update(
        gl,
        std::mem::size_of::<Entry>() * entry_idx,
        &new_index as *const u32 as *const u8,
        std::mem::size_of::<u32>(),
      );
    }
  }

  pub fn draw(&self, _gl: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.gl_array.gl_id);
      gl::DrawArraysInstanced(gl::TRIANGLES, 0, 18, self.index_to_id.len() as i32);
    }
  }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::audionode::MAX_CHANNEL_COUNT;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::window::Window;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSAutoCompartment, JSContext, JSObject};
use js::jsapi::JS_GetArrayBufferViewBuffer;
use js::rust::CustomAutoRooterGuard;
use js::rust::wrappers::JS_DetachArrayBuffer;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

// This range is defined by the spec.
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer
pub const MIN_SAMPLE_RATE: f32 = 8000.;
pub const MAX_SAMPLE_RATE: f32 = 96000.;

type JSAudioChannel = Heap<*mut JSObject>;

#[dom_struct]
pub struct AudioBuffer {
    reflector_: Reflector,
    js_channels: DomRefCell<Vec<JSAudioChannel>>,
    #[ignore_malloc_size_of = "servo_media"]
    shared_channels: DomRefCell<ServoMediaAudioBuffer>,
    sample_rate: f32,
    length: u32,
    duration: f64,
    number_of_channels: u32,
}

impl AudioBuffer {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(number_of_channels: u32, length: u32, sample_rate: f32) -> AudioBuffer {
        let vec = (0..number_of_channels).map(|_| Heap::default()).collect();
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(vec),
            shared_channels: DomRefCell::new(ServoMediaAudioBuffer::new(
                number_of_channels as u8,
                length as usize,
            )),
            sample_rate,
            length,
            duration: length as f64 / sample_rate as f64,
            number_of_channels,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[Vec<f32>]>,
    ) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(number_of_channels, length, sample_rate);
        let buffer = reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap);
        buffer.set_channels(initial_data);
        buffer
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-audiobuffer
    pub fn Constructor(
        window: &Window,
        options: &AudioBufferOptions,
    ) -> Fallible<DomRoot<AudioBuffer>> {
        if options.length <= 0 ||
            options.numberOfChannels <= 0 ||
            options.numberOfChannels > MAX_CHANNEL_COUNT ||
            *options.sampleRate < MIN_SAMPLE_RATE ||
            *options.sampleRate > MAX_SAMPLE_RATE
        {
            return Err(Error::NotSupported);
        }
        Ok(AudioBuffer::new(
            window,
            options.numberOfChannels,
            options.length,
            *options.sampleRate,
            None,
        ))
    }

    // Initialize the underlying channels data with initial data provided by
    // the user or silence otherwise.
    #[allow(unsafe_code)]
    pub fn set_channels(&self, initial_data: Option<&[Vec<f32>]>) {
        for channel in 0..self.number_of_channels {
            (*self.shared_channels.borrow_mut()).buffers[channel as usize] = match initial_data {
                Some(data) => data[channel as usize].clone(),
                None => vec![0.; self.length as usize],
            };
        }
    }

    pub fn get_channels(&self) -> ServoMediaAudioBuffer {
        self.shared_channels.borrow().clone()
    }

    #[allow(unsafe_code)]
    unsafe fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        let global = self.global();
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                continue;
            }

            // Copy the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let shared_channel = &(*self.shared_channels.borrow_mut()).buffers[i];
            if Float32Array::create(cx, CreateWith::Slice(shared_channel), array.handle_mut())
                .is_err()
            {
                return false;
            }
            channel.set(array.get());
        }

        true
    }

    // https://webaudio.github.io/web-audio-api/#acquire-the-content
    #[allow(unsafe_code)]
    pub fn acquire_contents(&self) -> Option<ServoMediaAudioBuffer> {
        let cx = self.global().get_cx();
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            // Step 1.
            if channel.get().is_null() {
                return None;
            }

            // Step 2.
            let channel_data = unsafe {
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    let data = array.to_vec();
                    let mut is_shared = false;
                    rooted!(in (cx) let view_buffer =
                        JS_GetArrayBufferViewBuffer(cx, channel.handle(), &mut is_shared));
                    // This buffer is always created unshared
                    debug_assert!(!is_shared);
                    let _ = JS_DetachArrayBuffer(cx, view_buffer.handle());
                    data
                } else {
                    return None;
                }
            };

            channel.set(ptr::null_mut());

            // Step 3.
            (*self.shared_channels.borrow_mut()).buffers[i] = channel_data;

            // Step 4 will complete turning shared_channels
            // data into js_channels ArrayBuffers in restore_js_channel_data.
        }

        Some((*self.shared_channels.borrow()).clone())
    }
}

impl AudioBufferMethods for AudioBuffer {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
    fn Length(&self) -> u32 {
        self.length
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
    fn Duration(&self) -> Finite<f64> {
        Finite::wrap(self.duration)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
    fn NumberOfChannels(&self) -> u32 {
        self.number_of_channels
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
    #[allow(unsafe_code)]
    unsafe fn GetChannelData(
        &self,
        cx: *mut JSContext,
        channel: u32,
    ) -> Fallible<NonNull<JSObject>> {
        if channel >= self.number_of_channels {
            return Err(Error::IndexSize);
        }

        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        Ok(NonNull::new_unchecked(
            self.js_channels.borrow()[channel as usize].get(),
        ))
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
    #[allow(unsafe_code)]
    fn CopyFromChannel(
        &self,
        mut destination: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if destination.is_shared() {
            return Err(Error::Type("Cannot copy to shared buffer".to_owned()));
        }

        if channel_number >= self.number_of_channels || start_in_channel >= self.length {
            return Err(Error::IndexSize);
        }

        let bytes_to_copy = min(self.length - start_in_channel, destination.len() as u32) as usize;
        let cx = self.global().get_cx();
        let channel_number = channel_number as usize;
        let offset = start_in_channel as usize;
        let mut dest = Vec::with_capacity(destination.len());

        // We either copy form js_channels or shared_channels.
        let js_channel = self.js_channels.borrow()[channel_number].get();
        if !js_channel.is_null() {
            typedarray!(in(cx) let array: Float32Array = js_channel);
            if let Ok(array) = array {
                let data = unsafe { array.as_slice() };
                dest.extend_from_slice(&data[offset..offset + bytes_to_copy]);
            }
        } else if let Some(shared_channel) = self.shared_channels.borrow().buffers.get(channel_number) {
            dest.extend_from_slice(&shared_channel.as_slice()[offset..offset + bytes_to_copy]);
        }

        unsafe {
            destination.update(&dest);
        }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
    #[allow(unsafe_code)]
    fn CopyToChannel(
        &self,
        source: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if source.is_shared() {
            return Err(Error::Type("Cannot copy from shared buffer".to_owned()));
        }

        if channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if unsafe { !self.restore_js_channel_data(cx) } {
            return Err(Error::JSFailed);
        }

        let js_channel = self.js_channels.borrow()[channel_number as usize].get();
        if js_channel.is_null() {
            // The array buffer was detached.
            return Err(Error::IndexSize);
        }

        typedarray!(in(cx) let js_channel: Float32Array = js_channel);
        if let Ok(mut js_channel) = js_channel {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            unsafe {
                let data = &source.as_slice()[0..bytes_to_copy];
                // Update shared channel.
                let mut shared_channels = self.shared_channels.borrow_mut();
                let shared_channel = shared_channels.data_chan_mut(channel_number as u8);
                let (_, mut shared_channel) = shared_channel.split_at_mut(start_in_channel as usize);
                shared_channel[0..bytes_to_copy].copy_from_slice(data);
                // Update js channel.
                js_channel.update(data);
            }
        } else {
            return Err(Error::IndexSize);
        }

        Ok(())
    }
}
<commit_msg>Keep shared and js channels in sync<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::audionode::MAX_CHANNEL_COUNT;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::window::Window;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSAutoCompartment, JSContext, JSObject};
use js::jsapi::JS_GetArrayBufferViewBuffer;
use js::rust::CustomAutoRooterGuard;
use js::rust::wrappers::JS_DetachArrayBuffer;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

// This range is defined by the spec.
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer
pub const MIN_SAMPLE_RATE: f32 = 8000.;
pub const MAX_SAMPLE_RATE: f32 = 96000.;

type JSAudioChannel = Heap<*mut JSObject>;

#[dom_struct]
pub struct AudioBuffer {
    reflector_: Reflector,
    js_channels: DomRefCell<Vec<JSAudioChannel>>,
    #[ignore_malloc_size_of = "servo_media"]
    shared_channels: DomRefCell<ServoMediaAudioBuffer>,
    sample_rate: f32,
    length: u32,
    duration: f64,
    number_of_channels: u32,
}

impl AudioBuffer {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(number_of_channels: u32, length: u32, sample_rate: f32) -> AudioBuffer {
        let vec = (0..number_of_channels).map(|_| Heap::default()).collect();
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(vec),
            shared_channels: DomRefCell::new(ServoMediaAudioBuffer::new(
                number_of_channels as u8,
                length as usize,
            )),
            sample_rate,
            length,
            duration: length as f64 / sample_rate as f64,
            number_of_channels,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[Vec<f32>]>,
    ) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(number_of_channels, length, sample_rate);
        let buffer = reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap);
        buffer.set_channels(initial_data);
        buffer
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-audiobuffer
    pub fn Constructor(
        window: &Window,
        options: &AudioBufferOptions,
    ) -> Fallible<DomRoot<AudioBuffer>> {
        if options.length <= 0 ||
            options.numberOfChannels <= 0 ||
            options.numberOfChannels > MAX_CHANNEL_COUNT ||
            *options.sampleRate < MIN_SAMPLE_RATE ||
            *options.sampleRate > MAX_SAMPLE_RATE
        {
            return Err(Error::NotSupported);
        }
        Ok(AudioBuffer::new(
            window,
            options.numberOfChannels,
            options.length,
            *options.sampleRate,
            None,
        ))
    }

    // Initialize the underlying channels data with initial data provided by
    // the user or silence otherwise.
    #[allow(unsafe_code)]
    pub fn set_channels(&self, initial_data: Option<&[Vec<f32>]>) {
        for channel in 0..self.number_of_channels {
            (*self.shared_channels.borrow_mut()).buffers[channel as usize] = match initial_data {
                Some(data) => data[channel as usize].clone(),
                None => vec![0.; self.length as usize],
            };
        }
    }

    pub fn get_channels(&self) -> ServoMediaAudioBuffer {
        self.shared_channels.borrow().clone()
    }

    #[allow(unsafe_code)]
    unsafe fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        let global = self.global();
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                // We may have called GetChannelData, and web content may have modified
                // js_channels. So make sure that shared_channels contains the same data as
                // js_channels.
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    (*self.shared_channels.borrow_mut()).buffers[i] = array.to_vec();
                }
                continue;
            }

            // Copy the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            if Float32Array::create(cx, CreateWith::Slice(&(*self.shared_channels.borrow_mut()).buffers[i]), array.handle_mut())
                .is_err()
            {
                return false;
            }
            channel.set(array.get());
        }

        true
    }

    // https://webaudio.github.io/web-audio-api/#acquire-the-content
    #[allow(unsafe_code)]
    pub fn acquire_contents(&self) -> Option<ServoMediaAudioBuffer> {
        let cx = self.global().get_cx();
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            // Step 1.
            if channel.get().is_null() {
                return None;
            }

            // Step 2.
            let channel_data = unsafe {
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    let data = array.to_vec();
                    let mut is_shared = false;
                    rooted!(in (cx) let view_buffer =
                        JS_GetArrayBufferViewBuffer(cx, channel.handle(), &mut is_shared));
                    // This buffer is always created unshared
                    debug_assert!(!is_shared);
                    let _ = JS_DetachArrayBuffer(cx, view_buffer.handle());
                    data
                } else {
                    return None;
                }
            };

            channel.set(ptr::null_mut());

            // Step 3.
            (*self.shared_channels.borrow_mut()).buffers[i] = channel_data;

            // Step 4 will complete turning shared_channels
            // data into js_channels ArrayBuffers in restore_js_channel_data.
        }

        Some((*self.shared_channels.borrow()).clone())
    }
}

impl AudioBufferMethods for AudioBuffer {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
    fn Length(&self) -> u32 {
        self.length
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
    fn Duration(&self) -> Finite<f64> {
        Finite::wrap(self.duration)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
    fn NumberOfChannels(&self) -> u32 {
        self.number_of_channels
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
    #[allow(unsafe_code)]
    unsafe fn GetChannelData(
        &self,
        cx: *mut JSContext,
        channel: u32,
    ) -> Fallible<NonNull<JSObject>> {
        if channel >= self.number_of_channels {
            return Err(Error::IndexSize);
        }

        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        Ok(NonNull::new_unchecked(
            self.js_channels.borrow()[channel as usize].get(),
        ))
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
    #[allow(unsafe_code)]
    fn CopyFromChannel(
        &self,
        mut destination: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if destination.is_shared() {
            return Err(Error::Type("Cannot copy to shared buffer".to_owned()));
        }

        if channel_number >= self.number_of_channels || start_in_channel >= self.length {
            return Err(Error::IndexSize);
        }

        let bytes_to_copy = min(self.length - start_in_channel, destination.len() as u32) as usize;
        let cx = self.global().get_cx();
        let channel_number = channel_number as usize;
        let offset = start_in_channel as usize;
        let mut dest = Vec::with_capacity(destination.len());

        // We either copy form js_channels or shared_channels.
        let js_channel = self.js_channels.borrow()[channel_number].get();
        if !js_channel.is_null() {
            typedarray!(in(cx) let array: Float32Array = js_channel);
            if let Ok(array) = array {
                let data = unsafe { array.as_slice() };
                dest.extend_from_slice(&data[offset..offset + bytes_to_copy]);
            }
        } else if let Some(shared_channel) = self.shared_channels.borrow().buffers.get(channel_number) {
            dest.extend_from_slice(&shared_channel.as_slice()[offset..offset + bytes_to_copy]);
        }

        unsafe {
            destination.update(&dest);
        }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
    #[allow(unsafe_code)]
    fn CopyToChannel(
        &self,
        source: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if source.is_shared() {
            return Err(Error::Type("Cannot copy from shared buffer".to_owned()));
        }

        if channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if unsafe { !self.restore_js_channel_data(cx) } {
            return Err(Error::JSFailed);
        }

        let js_channel = self.js_channels.borrow()[channel_number as usize].get();
        if js_channel.is_null() {
            // The array buffer was detached.
            return Err(Error::IndexSize);
        }

        typedarray!(in(cx) let js_channel: Float32Array = js_channel);
        if let Ok(mut js_channel) = js_channel {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            unsafe {
                let data = &source.as_slice()[0..bytes_to_copy];
                // Update shared channel.
                {
                    let mut shared_channels = self.shared_channels.borrow_mut();
                    let shared_channel = shared_channels.data_chan_mut(channel_number as u8);
                    let (_, mut shared_channel) = shared_channel.split_at_mut(start_in_channel as usize);
                    shared_channel[0..bytes_to_copy].copy_from_slice(data);
                }
                // Update js channel.
                js_channel.update(self.shared_channels.borrow().buffers[channel_number as usize].as_slice());
            }
        } else {
            return Err(Error::IndexSize);
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-tidy-linelength

struct Bar<'x, 'y, 'z> { bar: &'y isize, baz: isize }
fn bar1<'a>(x: &Bar) -> (&'a isize, &'a isize, &'a isize) {
//~^ HELP: consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a isize, &'a isize, &'a isize)
    (x.bar, &x.baz, &x.baz)
    //~^ ERROR: cannot infer
    //~^^ ERROR: cannot infer
    //~^^^ ERROR: cannot infer
}

fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a isize, &'a isize, &'a isize) {
//~^ HELP: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a isize, &'a isize, &'a isize)
    (x.bar, &x.baz, &x.baz)
    //~^ ERROR: cannot infer
    //~^^ ERROR: cannot infer
    //~^^^ ERROR: cannot infer
}

fn main() { }
<commit_msg>Modify lifetime-infereence-give-expl-lifetime-param-3 to use a shorter type name so that messages do not wrap.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-tidy-linelength

struct Bar<'x, 'y, 'z> { bar: &'y i32, baz: i32 }
fn bar1<'a>(x: &Bar) -> (&'a i32, &'a i32, &'a i32) {
//~^ HELP: consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a i32, &'a i32, &'a i32)
    (x.bar, &x.baz, &x.baz)
    //~^ ERROR: cannot infer
    //~^^ ERROR: cannot infer
    //~^^^ ERROR: cannot infer
}

fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a i32, &'a i32, &'a i32) {
//~^ HELP: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a i32, &'a i32, &'a i32)
    (x.bar, &x.baz, &x.baz)
    //~^ ERROR: cannot infer
    //~^^ ERROR: cannot infer
    //~^^^ ERROR: cannot infer
}

fn main() { }
<|endoftext|>