<commit_before>use bifrost::vector_clock::{VectorClock, StandardVectorClock, ServerVectorClock};
use bifrost::utils::time::get_time;
use chashmap::{CHashMap, WriteGuard};
use std::collections::{BTreeMap, BTreeSet, HashMap};
use ram::types::{Id};
use ram::cell::{Cell, ReadError, WriteError};
use server::NebServer;
use parking_lot::Mutex;
use std::sync::mpsc::{channel, Sender, Receiver};
use futures;
use super::*;

type TxnAwaits = Arc<Mutex<HashMap<u64, Arc<AwaitingServer>>>>;
type TxnGuard<'a> = WriteGuard<'a, TransactionId, Transaction>;
type ChangedObjs = BTreeMap<u64, Vec<(Id, DataObject)>>;
type DataSiteClients = HashMap<u64, Arc<data_site::AsyncServiceClient>>;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(TNX_MANAGER_RPC_SERVICE) as u64;

#[derive(Debug, Serialize, Deserialize)]
pub enum TMError {
    TransactionNotFound,
    CannotLocateCellServer,
    NoResponseFromCellServer,
    AssertionError
}

#[derive(Clone)]
struct DataObject {
    server: u64,
    cell: Option<Cell>,
    new: bool
}

struct Transaction {
    start_time: i64, // use for timeout detecting
    id: TransactionId,
    data: BTreeMap<Id, DataObject>,
    writes: BTreeSet<Id>,
}

service! {
    rpc begin() -> TransactionId;
    rpc read(tid: TransactionId, id: Id) -> TransactionExecResult<Cell, ReadError> | TMError;
    rpc write(tid: TransactionId, id: Id, cell: Cell) -> TransactionExecResult<(), WriteError> | TMError;
    rpc update(tid: TransactionId, cell: Cell) -> TransactionExecResult<(), WriteError> | TMError;
    rpc remove(tid: TransactionId, id: Id) -> TransactionExecResult<(), WriteError> | TMError;

    rpc prepare(tid: TransactionId) -> PrepareResult | TMError;
    rpc commit(tid: TransactionId);
    rpc abort(tid: TransactionId);

    rpc go_ahead(tid: BTreeSet<TransactionId>); // invoked by data site to continue on it's transaction in case of waiting
}

pub struct TransactionManager {
    server: Arc<NebServer>,
    transactions: CHashMap<TransactionId, Transaction>,
    data_sites: CHashMap<u64, Arc<data_site::AsyncServiceClient>>,
    await_manager: AwaitManager
}
dispatch_rpc_service_functions!(TransactionManager);

impl TransactionManager {
    pub fn new(server: &Arc<NebServer>) -> Arc<TransactionManager> {
        Arc::new(TransactionManager {
            server: server.clone(),
            transactions: CHashMap::new(),
            data_sites: CHashMap::new(),
            await_manager: AwaitManager::new()
        })
    }
}

impl TransactionManager {
    fn server_id(&self) -> u64 {
        self.server.server_id
    }
    fn get_data_site(&self, server_id: u64) -> io::Result<Arc<data_site::AsyncServiceClient>> {
        if !self.data_sites.contains_key(&server_id) {
            let client = self.server.get_member_by_server_id(server_id)?;
            self.data_sites.upsert(server_id, || {
                data_site::AsyncServiceClient::new(DEFAULT_SERVICE_ID, &client)
            }, |_| {});
        }
        Ok(self.data_sites .get(&server_id).unwrap().clone())
    }
    fn get_data_site_by_id(&self, id: &Id) -> io::Result<(u64, Arc<data_site::AsyncServiceClient>)> {
        match self.server.get_server_id_by_id(id) {
            Some(id) => match self.get_data_site(id) {
                Ok(site) => Ok((id, site.clone())),
                Err(e) => Err(e)
            },
            _ => Err(io::Error::new(io::ErrorKind::NotFound, "cannot find data site for this id"))
        }
    }
    fn get_clock(&self) -> StandardVectorClock {
        self.server.txn_peer.clock.to_clock()
    }
    fn merge_clock(&self, clock: &StandardVectorClock) {
        self.server.txn_peer.clock.merge_with(clock)
    }
    fn get_transaction(&self, tid: &TransactionId) -> Result<TxnGuard, TMError> {
        match self.transactions.get_mut(tid) {
            Some(tnx) => Ok(tnx),
            _ => {Err(TMError::TransactionNotFound)}
        }
    }
    fn changed_objs(&self, txn: &TxnGuard) -> ChangedObjs {
        let mut changed_objs: BTreeMap<u64, Vec<(Id, DataObject)>> = BTreeMap::new();
        for (id, data_obj) in &txn.data {
            changed_objs.entry(data_obj.server).or_insert_with(|| Vec::new()).push((*id, data_obj.clone()));
        }
        changed_objs
    }
    fn data_sites(&self, changed_objs: &ChangedObjs) -> Result<DataSiteClients, TMError>  {
        let data_sites: HashMap<u64, _> = changed_objs.iter().map(|(server_id, _)| {
            (*server_id, self.get_data_site(*server_id))
        }).collect();
        if data_sites.iter().any(|(_, data_site)| { data_site.is_err() }) {
            return Err(TMError::CannotLocateCellServer)
        }
        Ok(data_sites.into_iter().map(
            |(server_id, data_site)| {
                (server_id, data_site.unwrap())
            }
        ).collect())
    }
    fn site_prepare(
        server: Arc<NebServer>,
        tid: &TransactionId,
        objs: &Vec<(Id, DataObject)>,
        data_site: &Arc<data_site::AsyncServiceClient>
    ) -> Box<futures::Future<Item = PrepareResult, Error = TMError>> {
        let self_server_id = server.server_id;
        let cell_ids: Vec<_> = objs.iter().map(|&(id, _)| id).collect();
        let res_future = data_site
            .prepare(&self_server_id, &server.txn_peer.clock.to_clock(), tid, &cell_ids)
            .map_err(|_| -> TMError {
                TMError::NoResponseFromCellServer
            })
            .map(move |prepare_res| -> PrepareResult {
                let prepare_res = prepare_res.unwrap();
                server.txn_peer.clock.merge_with(&prepare_res.clock);
                prepare_res.payload
            })
            .then(|prepare_payload| {
                match prepare_payload {
                    Ok(payload) => {
                        match payload {
                            PrepareResult::Wait => {
                                return Ok(payload)
                            },
                            _ => {
                                return Ok(payload)
                            }
                        }
                    },
                    Err(e) => Err(e)
                }
            });
        Box::new(res_future)
    }
    fn sites_prepare(&self, tid: &TransactionId, txn: Transaction, changed_objs: &ChangedObjs, data_sites: DataSiteClients) {
        let prepare_futures: Vec<_> = changed_objs.iter().map(|(server, objs)| {
            let data_site = data_sites.get(&server).unwrap();
            TransactionManager::site_prepare(
                self.server.clone(), tid, objs, data_site
            )
        }).collect();
        let prepare_result = future::join_all(prepare_futures).wait();
    }
}

impl Service for TransactionManager {
    fn begin(&self) -> Result<TransactionId, ()> {
        let id = self.server.txn_peer.clock.inc();
        self.transactions.insert(id.clone(), Transaction {
            start_time: get_time(),
            id: id.clone(),
            data: BTreeMap::new(),
            writes: BTreeSet::new()
        });
        Ok(id)
    }
    fn read(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<Cell, ReadError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        if let Some(dataObj) = txn.data.get(id) {
            match dataObj.cell {
                Some(ref cell) => {
                    return Ok(TransactionExecResult::Accepted(cell.clone())) // read from cache
                },
                None => {
                   return Ok(TransactionExecResult::Error(ReadError::CellDoesNotExisted))
                }
            }
        }
        let server = self.get_data_site_by_id(&id);
        match server {
            Ok((server_id, server)) => {
                let self_server_id = self.server.server_id;
                let read_response = server.read(
                    &self_server_id,
                    &self.get_clock(),
                    tid, id
                ).wait();
                match read_response {
                    Ok(dsr) => {
                        let dsr = dsr.unwrap();
                        self.merge_clock(&dsr.clock);
                        match dsr.payload {
                            TransactionExecResult::Accepted(ref cell) => {
                                txn.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: Some(cell.clone()),
                                    new: false,
                                });
                            },
                            TransactionExecResult::Error(ReadError::CellDoesNotExisted) => {
                                txn.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: None,
                                    new: false,
                                });
                            }
                            TransactionExecResult::Wait => {} // TODO: deal with wait
                            _ => {}
                        }
                        Ok(dsr.payload)
                    },
                    Err(e) => {
                        error!("{:?}", e);
                        Err(TMError::NoResponseFromCellServer)
                    }
                }
            },
            Err(e) => {
                error!("{:?}", e);
                Err(TMError::CannotLocateCellServer)
            }
        }
    }
    fn write(&self, tid: &TransactionId, id: &Id, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        match self.server.get_server_id_by_id(id) {
            Some(server_id) => {
                let have_cached_cell = txn.data.contains_key(id);
                if !have_cached_cell {
                    txn.data.insert(*id, DataObject {
                        server: server_id,
                        cell: Some(cell.clone()),
                        new: true,
                    });
                    Ok(TransactionExecResult::Accepted(()))
                } else {
                    let mut data_obj = txn.data.get_mut(id).unwrap();
                    if !data_obj.cell.is_none() {
                        return Ok(TransactionExecResult::Error(WriteError::CellAlreadyExisted))
                    }
                    data_obj.cell = Some(cell.clone());
                    Ok(TransactionExecResult::Accepted(()))
                }
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn update(&self, tid: &TransactionId, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        let id = cell.id();
        match self.server.get_server_id_by_id(&id) {
            Some(server_id) => {
                let cell = cell.clone();
                if txn.data.contains_key(&id) {
                    txn.data.get_mut(&id).unwrap().cell = Some(cell)
                } else {
                    txn.data.insert(id, DataObject {
                        server: server_id,
                        cell: Some(cell),
                        new: false,
                    });
                }
                Ok(TransactionExecResult::Accepted(()))
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn remove(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        match self.server.get_server_id_by_id(&id) {
            Some(server_id) => {
                if txn.data.contains_key(&id) {
                    let data_obj = txn.data.get_mut(&id).unwrap();
                    if data_obj.cell.is_none() {
                        return Ok(TransactionExecResult::Error(WriteError::CellDoesNotExisted))
                    }
                    data_obj.cell = None;
                } else {
                    txn.data.insert(*id, DataObject {
                        server: server_id,
                        cell: None,
                        new: false,
                    });
                }
                Ok(TransactionExecResult::Accepted(()))
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn prepare(&self, tid: &TransactionId) -> Result<PrepareResult, TMError> {
        let mut txn = self.get_transaction(tid)?;
        let mut changed_objs = self.changed_objs(&txn);
        let data_sites = self.data_sites(&changed_objs)?;
        Err(TMError::CannotLocateCellServer)
    }
    fn commit(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn abort(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn go_ahead(&self, tid: &BTreeSet<TransactionId>) -> Result<(), ()> {
        Err(())
    }
}

struct AwaitingServer {
    sender: Mutex<Sender<()>>,
    receiver: Mutex<Receiver<()>>,
}

impl AwaitingServer {
    pub fn new() -> AwaitingServer {
        let (sender, receiver) = channel();
        AwaitingServer {
            sender: Mutex::new(sender),
            receiver: Mutex::new(receiver)
        }
    }
    pub fn send(&self) {
        self.sender.lock().send(());
    }
    pub fn wait(&self) {
        self.receiver.lock().recv();
    }
}

struct AwaitManager {
    channels: Mutex<HashMap<TransactionId, TxnAwaits>>
}

impl AwaitManager {
    pub fn new() -> AwaitManager {
        AwaitManager {
            channels: Mutex::new(HashMap::new())
        }
    }
    pub fn get_txn(&self, tid: &TransactionId) -> TxnAwaits {
        self.channels.lock()
            .entry(tid.clone())
            .or_insert_with(|| Arc::new(Mutex::new(HashMap::new())))
            .clone()
    }
    pub fn server_from_awaits(awaits: TxnAwaits, server_id: u64) -> Arc<AwaitingServer> {
        awaits.lock()
            .entry(server_id)
            .or_insert_with(|| Arc::new(AwaitingServer::new()))
            .clone()
    }
}<commit_msg>TM prepare completed<commit_after>use bifrost::vector_clock::{VectorClock, StandardVectorClock, ServerVectorClock};
use bifrost::utils::time::get_time;
use chashmap::{CHashMap, WriteGuard};
use std::collections::{BTreeMap, BTreeSet, HashMap};
use ram::types::{Id};
use ram::cell::{Cell, ReadError, WriteError};
use server::NebServer;
use parking_lot::Mutex;
use std::sync::mpsc::{channel, Sender, Receiver};
use futures;
use super::*;

type TxnAwaits = Arc<Mutex<HashMap<u64, Arc<AwaitingServer>>>>;
type TxnGuard<'a> = WriteGuard<'a, TransactionId, Transaction>;
type ChangedObjs = BTreeMap<u64, Vec<(Id, DataObject)>>;
type DataSiteClients = HashMap<u64, Arc<data_site::AsyncServiceClient>>;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(TNX_MANAGER_RPC_SERVICE) as u64;

#[derive(Debug, Serialize, Deserialize)]
pub enum TMError {
    TransactionNotFound,
    CannotLocateCellServer,
    NoResponseFromCellServer,
    AssertionError
}

#[derive(Clone)]
struct DataObject {
    server: u64,
    cell: Option<Cell>,
    new: bool
}

struct Transaction {
    start_time: i64, // use for timeout detecting
    id: TransactionId,
    data: BTreeMap<Id, DataObject>,
    writes: BTreeSet<Id>,
}

service! {
    rpc begin() -> TransactionId;
    rpc read(tid: TransactionId, id: Id) -> TransactionExecResult<Cell, ReadError> | TMError;
    rpc write(tid: TransactionId, id: Id, cell: Cell) -> TransactionExecResult<(), WriteError> | TMError;
    rpc update(tid: TransactionId, cell: Cell) -> TransactionExecResult<(), WriteError> | TMError;
    rpc remove(tid: TransactionId, id: Id) -> TransactionExecResult<(), WriteError> | TMError;

    rpc prepare(tid: TransactionId) -> PrepareResult | TMError;
    rpc commit(tid: TransactionId);
    rpc abort(tid: TransactionId);

    rpc go_ahead(tid: BTreeSet<TransactionId>); // invoked by data site to continue on it's transaction in case of waiting
}

pub struct TransactionManager {
    server: Arc<NebServer>,
    transactions: CHashMap<TransactionId, Transaction>,
    data_sites: CHashMap<u64, Arc<data_site::AsyncServiceClient>>,
    await_manager: AwaitManager
}
dispatch_rpc_service_functions!(TransactionManager);

impl TransactionManager {
    pub fn new(server: &Arc<NebServer>) -> Arc<TransactionManager> {
        Arc::new(TransactionManager {
            server: server.clone(),
            transactions: CHashMap::new(),
            data_sites: CHashMap::new(),
            await_manager: AwaitManager::new()
        })
    }
}

impl TransactionManager {
    fn server_id(&self) -> u64 {
        self.server.server_id
    }
    fn get_data_site(&self, server_id: u64) -> io::Result<Arc<data_site::AsyncServiceClient>> {
        if !self.data_sites.contains_key(&server_id) {
            let client = self.server.get_member_by_server_id(server_id)?;
            self.data_sites.upsert(server_id, || {
                data_site::AsyncServiceClient::new(DEFAULT_SERVICE_ID, &client)
            }, |_| {});
        }
        Ok(self.data_sites .get(&server_id).unwrap().clone())
    }
    fn get_data_site_by_id(&self, id: &Id) -> io::Result<(u64, Arc<data_site::AsyncServiceClient>)> {
        match self.server.get_server_id_by_id(id) {
            Some(id) => match self.get_data_site(id) {
                Ok(site) => Ok((id, site.clone())),
                Err(e) => Err(e)
            },
            _ => Err(io::Error::new(io::ErrorKind::NotFound, "cannot find data site for this id"))
        }
    }
    fn get_clock(&self) -> StandardVectorClock {
        self.server.txn_peer.clock.to_clock()
    }
    fn merge_clock(&self, clock: &StandardVectorClock) {
        self.server.txn_peer.clock.merge_with(clock)
    }
    fn get_transaction(&self, tid: &TransactionId) -> Result<TxnGuard, TMError> {
        match self.transactions.get_mut(tid) {
            Some(tnx) => Ok(tnx),
            _ => {Err(TMError::TransactionNotFound)}
        }
    }
    fn changed_objs(&self, txn: &TxnGuard) -> ChangedObjs {
        let mut changed_objs: BTreeMap<u64, Vec<(Id, DataObject)>> = BTreeMap::new();
        for (id, data_obj) in &txn.data {
            changed_objs.entry(data_obj.server).or_insert_with(|| Vec::new()).push((*id, data_obj.clone()));
        }
        changed_objs
    }
    fn data_sites(&self, changed_objs: &ChangedObjs) -> Result<DataSiteClients, TMError>  {
        let data_sites: HashMap<u64, _> = changed_objs.iter().map(|(server_id, _)| {
            (*server_id, self.get_data_site(*server_id))
        }).collect();
        if data_sites.iter().any(|(_, data_site)| { data_site.is_err() }) {
            return Err(TMError::CannotLocateCellServer)
        }
        Ok(data_sites.into_iter().map(
            |(server_id, data_site)| {
                (server_id, data_site.unwrap())
            }
        ).collect())
    }
    fn site_prepare(
        server: Arc<NebServer>, awaits: TxnAwaits, tid: TransactionId, objs: Vec<(Id, DataObject)>,
        data_site: Arc<data_site::AsyncServiceClient>
    ) -> Box<futures::Future<Item = PrepareResult, Error = TMError>> {
        let self_server_id = server.server_id;
        let cell_ids: Vec<_> = objs.iter().map(|&(id, _)| id).collect();
        let server_for_clock = server.clone();
        let res_future = data_site
            .prepare(&self_server_id, &server.txn_peer.clock.to_clock(), &tid, &cell_ids)
            .map_err(|_| -> TMError {
                TMError::NoResponseFromCellServer
            })
            .map(move |prepare_res| -> PrepareResult {
                let prepare_res = prepare_res.unwrap();
                server_for_clock.txn_peer.clock.merge_with(&prepare_res.clock);
                prepare_res.payload
            })
            .then(move |prepare_payload| {
                match prepare_payload {
                    Ok(payload) => {
                        match payload {
                            PrepareResult::Wait => {
                                AwaitManager::txn_wait(&awaits, data_site.server_id);
                                return TransactionManager::site_prepare(
                                    server, awaits, tid, objs, data_site
                                ).wait() // after waiting, retry
                            },
                            _ => {
                                return Ok(payload)
                            }
                        }
                    },
                    Err(e) => Err(e)
                }
            });
        Box::new(res_future)
    }
    fn sites_prepare(&self, tid: &TransactionId, changed_objs: ChangedObjs, data_sites: DataSiteClients)
        -> Result<PrepareResult, TMError> {
        let prepare_futures: Vec<_> = changed_objs.into_iter().map(|(server, objs)| {
            let data_site = data_sites.get(&server).unwrap().clone();
            TransactionManager::site_prepare(
                self.server.clone(),
                self.await_manager.get_txn(tid),
                tid.clone(), objs, data_site
            )
        }).collect();
        let prepare_results = future::join_all(prepare_futures).wait()?;
        for result in prepare_results {
            match result {
                PrepareResult::Success => {},
                _ => {return Ok(result)}
            }
        }
        Ok(PrepareResult::Success)
    }
}

impl Service for TransactionManager {
    fn begin(&self) -> Result<TransactionId, ()> {
        let id = self.server.txn_peer.clock.inc();
        self.transactions.insert(id.clone(), Transaction {
            start_time: get_time(),
            id: id.clone(),
            data: BTreeMap::new(),
            writes: BTreeSet::new()
        });
        Ok(id)
    }
    fn read(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<Cell, ReadError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        if let Some(dataObj) = txn.data.get(id) {
            match dataObj.cell {
                Some(ref cell) => {
                    return Ok(TransactionExecResult::Accepted(cell.clone())) // read from cache
                },
                None => {
                   return Ok(TransactionExecResult::Error(ReadError::CellDoesNotExisted))
                }
            }
        }
        let server = self.get_data_site_by_id(&id);
        match server {
            Ok((server_id, server)) => {
                let self_server_id = self.server.server_id;
                let read_response = server.read(
                    &self_server_id,
                    &self.get_clock(),
                    tid, id
                ).wait();
                match read_response {
                    Ok(dsr) => {
                        let dsr = dsr.unwrap();
                        self.merge_clock(&dsr.clock);
                        match dsr.payload {
                            TransactionExecResult::Accepted(ref cell) => {
                                txn.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: Some(cell.clone()),
                                    new: false,
                                });
                            },
                            TransactionExecResult::Error(ReadError::CellDoesNotExisted) => {
                                txn.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: None,
                                    new: false,
                                });
                            }
                            TransactionExecResult::Wait => {} // TODO: deal with wait
                            _ => {}
                        }
                        Ok(dsr.payload)
                    },
                    Err(e) => {
                        error!("{:?}", e);
                        Err(TMError::NoResponseFromCellServer)
                    }
                }
            },
            Err(e) => {
                error!("{:?}", e);
                Err(TMError::CannotLocateCellServer)
            }
        }
    }
    fn write(&self, tid: &TransactionId, id: &Id, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        match self.server.get_server_id_by_id(id) {
            Some(server_id) => {
                let have_cached_cell = txn.data.contains_key(id);
                if !have_cached_cell {
                    txn.data.insert(*id, DataObject {
                        server: server_id,
                        cell: Some(cell.clone()),
                        new: true,
                    });
                    Ok(TransactionExecResult::Accepted(()))
                } else {
                    let mut data_obj = txn.data.get_mut(id).unwrap();
                    if !data_obj.cell.is_none() {
                        return Ok(TransactionExecResult::Error(WriteError::CellAlreadyExisted))
                    }
                    data_obj.cell = Some(cell.clone());
                    Ok(TransactionExecResult::Accepted(()))
                }
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn update(&self, tid: &TransactionId, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        let id = cell.id();
        match self.server.get_server_id_by_id(&id) {
            Some(server_id) => {
                let cell = cell.clone();
                if txn.data.contains_key(&id) {
                    txn.data.get_mut(&id).unwrap().cell = Some(cell)
                } else {
                    txn.data.insert(id, DataObject {
                        server: server_id,
                        cell: Some(cell),
                        new: false,
                    });
                }
                Ok(TransactionExecResult::Accepted(()))
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn remove(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        match self.server.get_server_id_by_id(&id) {
            Some(server_id) => {
                if txn.data.contains_key(&id) {
                    let data_obj = txn.data.get_mut(&id).unwrap();
                    if data_obj.cell.is_none() {
                        return Ok(TransactionExecResult::Error(WriteError::CellDoesNotExisted))
                    }
                    data_obj.cell = None;
                } else {
                    txn.data.insert(*id, DataObject {
                        server: server_id,
                        cell: None,
                        new: false,
                    });
                }
                Ok(TransactionExecResult::Accepted(()))
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn prepare(&self, tid: &TransactionId) -> Result<PrepareResult, TMError> {
        let mut txn = self.get_transaction(tid)?;
        let mut changed_objs = self.changed_objs(&txn);
        let data_sites = self.data_sites(&changed_objs)?;
        self.sites_prepare(tid, changed_objs, data_sites)
    }
    fn commit(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn abort(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn go_ahead(&self, tid: &BTreeSet<TransactionId>) -> Result<(), ()> {
        Err(())
    }
}

struct AwaitingServer {
    sender: Mutex<Sender<()>>,
    receiver: Mutex<Receiver<()>>,
}

impl AwaitingServer {
    pub fn new() -> AwaitingServer {
        let (sender, receiver) = channel();
        AwaitingServer {
            sender: Mutex::new(sender),
            receiver: Mutex::new(receiver)
        }
    }
    pub fn send(&self) {
        self.sender.lock().send(());
    }
    pub fn wait(&self) {
        self.receiver.lock().recv();
    }
}

struct AwaitManager {
    channels: Mutex<HashMap<TransactionId, TxnAwaits>>
}

impl AwaitManager {
    pub fn new() -> AwaitManager {
        AwaitManager {
            channels: Mutex::new(HashMap::new())
        }
    }
    pub fn get_txn(&self, tid: &TransactionId) -> TxnAwaits {
        self.channels.lock()
            .entry(tid.clone())
            .or_insert_with(|| Arc::new(Mutex::new(HashMap::new())))
            .clone()
    }
    pub fn server_from_txn_awaits(awaits: &TxnAwaits, server_id: u64) -> Arc<AwaitingServer> {
        awaits.lock()
            .entry(server_id)
            .or_insert_with(|| Arc::new(AwaitingServer::new()))
            .clone()
    }
    pub fn txn_send(awaits: &TxnAwaits, server_id: u64) {
        AwaitManager::server_from_txn_awaits(awaits, server_id).send();
    }
    pub fn txn_wait(awaits: &TxnAwaits, server_id: u64) {
        AwaitManager::server_from_txn_awaits(awaits, server_id).wait();
    }
}<|endoftext|>


<commit_before>// spell-checker:ignore (ToDO) formatteriteminfo

use std::fmt;

#[derive(Copy)]
pub enum FormatWriter {
    IntWriter(fn(u64) -> String),
    FloatWriter(fn(f64) -> String),
    MultibyteWriter(fn(&[u8]) -> String),
}

impl Clone for FormatWriter {
    #[inline]
    fn clone(&self) -> Self {
        *self
    }
}

impl PartialEq for FormatWriter {
    fn eq(&self, other: &FormatWriter) -> bool {
        use crate::formatteriteminfo::FormatWriter::*;

        match (self, other) {
            (&IntWriter(ref a), &IntWriter(ref b)) => a == b,
            (&FloatWriter(ref a), &FloatWriter(ref b)) => a == b,
            (&MultibyteWriter(ref a), &MultibyteWriter(ref b)) => *a as usize == *b as usize,
            _ => false,
        }
    }
}

impl Eq for FormatWriter {}

impl fmt::Debug for FormatWriter {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FormatWriter::IntWriter(ref p) => {
                f.write_str("IntWriter:")?;
                fmt::Pointer::fmt(p, f)
            }
            FormatWriter::FloatWriter(ref p) => {
                f.write_str("FloatWriter:")?;
                fmt::Pointer::fmt(p, f)
            }
            FormatWriter::MultibyteWriter(ref p) => {
                f.write_str("MultibyteWriter:")?;
                fmt::Pointer::fmt(&(*p as *const ()), f)
            }
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct FormatterItemInfo {
    pub byte_size: usize,
    pub print_width: usize, // including a space in front of the text
    pub formatter: FormatWriter,
}
<commit_msg>refactor/od ~ fix `cargo clippy` complaint (*allow* clippy::enum_variant_names)<commit_after>// spell-checker:ignore (ToDO) formatteriteminfo

use std::fmt;

#[allow(clippy::enum_variant_names)]
#[derive(Copy)]
pub enum FormatWriter {
    IntWriter(fn(u64) -> String),
    FloatWriter(fn(f64) -> String),
    MultibyteWriter(fn(&[u8]) -> String),
}

impl Clone for FormatWriter {
    #[inline]
    fn clone(&self) -> Self {
        *self
    }
}

impl PartialEq for FormatWriter {
    fn eq(&self, other: &FormatWriter) -> bool {
        use crate::formatteriteminfo::FormatWriter::*;

        match (self, other) {
            (&IntWriter(ref a), &IntWriter(ref b)) => a == b,
            (&FloatWriter(ref a), &FloatWriter(ref b)) => a == b,
            (&MultibyteWriter(ref a), &MultibyteWriter(ref b)) => *a as usize == *b as usize,
            _ => false,
        }
    }
}

impl Eq for FormatWriter {}

impl fmt::Debug for FormatWriter {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FormatWriter::IntWriter(ref p) => {
                f.write_str("IntWriter:")?;
                fmt::Pointer::fmt(p, f)
            }
            FormatWriter::FloatWriter(ref p) => {
                f.write_str("FloatWriter:")?;
                fmt::Pointer::fmt(p, f)
            }
            FormatWriter::MultibyteWriter(ref p) => {
                f.write_str("MultibyteWriter:")?;
                fmt::Pointer::fmt(&(*p as *const ()), f)
            }
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct FormatterItemInfo {
    pub byte_size: usize,
    pub print_width: usize, // including a space in front of the text
    pub formatter: FormatWriter,
}
<|endoftext|>


<commit_before>use std::os;
use std::from_str::FromStr;

#[deriving(Eq)]
enum ConfigOption {
    Unsupported,
    Disabled,
    Enabled
}

impl ConfigOption {
    fn enabled(&self) -> bool {
        match *self {
            Enabled => true,
            _ => false
        }
    }
}

pub struct Config {
    max_size: uint,
    drawlist_count: uint,
    hmd_size: f32,
    bindless: ConfigOption,
    instanced: ConfigOption,
    profile: ConfigOption,
    opencl: ConfigOption
}

fn get_setting_option(name: &str, default: ConfigOption) -> ConfigOption {
   let is_set = match os::getenv(name) {
        Some(s) => {
            let s: ~str = s.chars().map(|c| c.to_lowercase()).collect();
            match s.as_slice() {
                "true" => Some(true),
                "enabled" => Some(true),
                "1" => Some(true),
                "false" => Some(false),
                "disabled" => Some(false),
                "0" => Some(false),
                _ => None
            }
        }
        None => None
    };

    match is_set {
        Some(true) => Enabled,
        Some(false) => Disabled,
        None => default
    }
}

fn check_gl_version(gl_version: (uint, uint), min: (uint, uint), if_supported: ConfigOption) -> ConfigOption {
    let (m_major, m_minor) = min;
    let (gl_major, gl_minor) = gl_version;

    if gl_major > m_major {
        if_supported
    } else if gl_major == m_major && gl_minor >= m_minor {
        if_supported
    } else {
        Unsupported
    }
}

fn get_setting_from_str<T: FromStr>(name: &str, default: T) -> T {
    let str_value = match os::getenv(name) {
        Some(s) => s,
        None => return default
    };

    match FromStr::from_str(str_value) {
        Some(v) => v,
        None => default
    }
}

impl Config
{
    pub fn new(gl_version: (uint, uint)) -> Config {
        Config {
            hmd_size: get_setting_from_str("HMD_SIZE", 1.5f32),
            max_size: get_setting_from_str("MAX_OBJECTS", 64u*1024),
            drawlist_count: get_setting_from_str("DRAWLIST_COUNT", 2u),
            opencl: get_setting_option("OPENCL_SUPPORT", Enabled),
            profile: get_setting_option("PROFILE", Disabled),
            bindless: check_gl_version(gl_version, (4, 4),
                get_setting_option("BINDLESS", Enabled)
            ),
            instanced: check_gl_version(gl_version, (3, 1),
                get_setting_option("INSTANCED", Enabled)
            ),
        }
    }

    pub fn use_bindless(&self) -> bool { self.bindless.enabled() }
    pub fn max_size(&self) -> uint { self.max_size }
    pub fn hmd_size(&self) -> f32 { self.hmd_size }
    pub fn profile(&self) -> bool { self.profile.enabled() }
    pub fn instanced(&self) -> bool { self.instanced.enabled() }
    pub fn opencl(&self) -> bool { self.opencl.enabled() }
    pub fn drawlist_count(&self) -> uint { self.drawlist_count }
}<commit_msg>updated config for drawlist of 3<commit_after>use std::os;
use std::from_str::FromStr;

#[deriving(Eq)]
enum ConfigOption {
    Unsupported,
    Disabled,
    Enabled
}

impl ConfigOption {
    fn enabled(&self) -> bool {
        match *self {
            Enabled => true,
            _ => false
        }
    }
}

pub struct Config {
    max_size: uint,
    drawlist_count: uint,
    hmd_size: f32,
    bindless: ConfigOption,
    instanced: ConfigOption,
    profile: ConfigOption,
    opencl: ConfigOption
}

fn get_setting_option(name: &str, default: ConfigOption) -> ConfigOption {
   let is_set = match os::getenv(name) {
        Some(s) => {
            let s: ~str = s.chars().map(|c| c.to_lowercase()).collect();
            match s.as_slice() {
                "true" => Some(true),
                "enabled" => Some(true),
                "1" => Some(true),
                "false" => Some(false),
                "disabled" => Some(false),
                "0" => Some(false),
                _ => None
            }
        }
        None => None
    };

    match is_set {
        Some(true) => Enabled,
        Some(false) => Disabled,
        None => default
    }
}

fn check_gl_version(gl_version: (uint, uint), min: (uint, uint), if_supported: ConfigOption) -> ConfigOption {
    let (m_major, m_minor) = min;
    let (gl_major, gl_minor) = gl_version;

    if gl_major > m_major {
        if_supported
    } else if gl_major == m_major && gl_minor >= m_minor {
        if_supported
    } else {
        Unsupported
    }
}

fn get_setting_from_str<T: FromStr>(name: &str, default: T) -> T {
    let str_value = match os::getenv(name) {
        Some(s) => s,
        None => return default
    };

    match FromStr::from_str(str_value) {
        Some(v) => v,
        None => default
    }
}

impl Config
{
    pub fn new(gl_version: (uint, uint)) -> Config {
        Config {
            hmd_size: get_setting_from_str("HMD_SIZE", 1.5f32),
            max_size: get_setting_from_str("MAX_OBJECTS", 64u*1024),
            drawlist_count: get_setting_from_str("DRAWLIST_COUNT", 3u),
            opencl: get_setting_option("OPENCL_SUPPORT", Enabled),
            profile: get_setting_option("PROFILE", Disabled),
            bindless: check_gl_version(gl_version, (4, 4),
                get_setting_option("BINDLESS", Enabled)
            ),
            instanced: check_gl_version(gl_version, (3, 1),
                get_setting_option("INSTANCED", Enabled)
            ),
        }
    }

    pub fn use_bindless(&self) -> bool { self.bindless.enabled() }
    pub fn max_size(&self) -> uint { self.max_size }
    pub fn hmd_size(&self) -> f32 { self.hmd_size }
    pub fn profile(&self) -> bool { self.profile.enabled() }
    pub fn instanced(&self) -> bool { self.instanced.enabled() }
    pub fn opencl(&self) -> bool { self.opencl.enabled() }
    pub fn drawlist_count(&self) -> uint { self.drawlist_count }
}<|endoftext|>


<commit_before>use id3v2::tag::frame::*;

pub mod id {
    pub const AENC_STR: &'static str = "AENC";
    pub const APIC_STR: &'static str = "APIC";
    pub const ASPI_STR: &'static str = "ASPI";
    pub const COMM_STR: &'static str = "COMM";
    pub const COMR_STR: &'static str = "COMR";
    pub const ENCR_STR: &'static str = "ENCR";
    pub const EQU2_STR: &'static str = "EQU2";
    // 2.3 only
    pub const EQUA_STR: &'static str = "EQUA";
    pub const ETCO_STR: &'static str = "ETCO";
    pub const GEOB_STR: &'static str = "GEOB";
    pub const GRID_STR: &'static str = "GRID";
    // 2.3 only
    pub const IPLS_STR: &'static str = "IPLS";
    pub const LINK_STR: &'static str = "LINK";
    pub const MCDI_STR: &'static str = "MCDI";
    pub const MLLT_STR: &'static str = "MLLT";
    pub const OWNE_STR: &'static str = "OWNE";
    pub const PRIV_STR: &'static str = "PRIV";
    pub const PCNT_STR: &'static str = "PCNT";
    pub const POPM_STR: &'static str = "POPM";
    pub const POSS_STR: &'static str = "POSS";
    pub const RBUF_STR: &'static str = "RBUF";
    // 2.3 only
    pub const RVAD_STR: &'static str = "RVAD";
    pub const RVA2_STR: &'static str = "RVA2";
    pub const RVRB_STR: &'static str = "RVRB";
    pub const SEEK_STR: &'static str = "SEEK";
    pub const SIGN_STR: &'static str = "SIGN";
    pub const SYLT_STR: &'static str = "SYLT";
    pub const SYTC_STR: &'static str = "SYTC";
    pub const TALB_STR: &'static str = "TALB";
    pub const TBPM_STR: &'static str = "TBPM";
    pub const TCOM_STR: &'static str = "TCOM";
    pub const TCON_STR: &'static str = "TCON";
    pub const TCOP_STR: &'static str = "TCOP";
    // 2.3 only
    pub const TDAT_STR: &'static str = "TDAT";
    pub const TDEN_STR: &'static str = "TDEN";
    pub const TDLY_STR: &'static str = "TDLY";
    pub const TDOR_STR: &'static str = "TDOR";
    pub const TDRC_STR: &'static str = "TDRC";
    pub const TDTG_STR: &'static str = "TDTG";
    pub const TDRL_STR: &'static str = "TDRL";
    pub const TENC_STR: &'static str = "TENC";
    pub const TEXT_STR: &'static str = "TEXT";
    pub const TFLT_STR: &'static str = "TFLT";
    // 2.3 only
    pub const TIME_STR: &'static str = "TIME";
    pub const TIPL_STR: &'static str = "TIPL";
    pub const TIT1_STR: &'static str = "TIT1";
    pub const TIT2_STR: &'static str = "TIT2";
    pub const TIT3_STR: &'static str = "TIT3";
    pub const TKEY_STR: &'static str = "TKEY";
    pub const TLAN_STR: &'static str = "TLAN";
    pub const TLEN_STR: &'static str = "TLEN";
    pub const TMCL_STR: &'static str = "TMCL";
    pub const TMED_STR: &'static str = "TMED";
    pub const TMOO_STR: &'static str = "TMOO";
    pub const TOAL_STR: &'static str = "TOAL";
    pub const TOFN_STR: &'static str = "TOFN";
    pub const TOLY_STR: &'static str = "TOLY";
    pub const TOPE_STR: &'static str = "TOPE";
    pub const TORY_STR: &'static str = "TORY";
    pub const TOWN_STR: &'static str = "TOWN";
    pub const TPE1_STR: &'static str = "TPE1";
    pub const TPE2_STR: &'static str = "TPE2";
    pub const TPE3_STR: &'static str = "TPE3";
    pub const TPE4_STR: &'static str = "TPE4";
    pub const TPOS_STR: &'static str = "TPOS";
    pub const TPRO_STR: &'static str = "TPRO";
    pub const TPUB_STR: &'static str = "TPUB";
    pub const TRCK_STR: &'static str = "TRCK";
    pub const TRDA_STR: &'static str = "TRDA";
    pub const TRSN_STR: &'static str = "TRSN";
    pub const TRSO_STR: &'static str = "TRSO";
    // 2.3 only
    pub const TSIZ_STR: &'static str = "TSIZ";
    pub const TSOA_STR: &'static str = "TSOA";
    pub const TSOP_STR: &'static str = "TSOP";
    pub const TSOT_STR: &'static str = "TSOT";
    pub const TSRC_STR: &'static str = "TSRC";
    pub const TSSE_STR: &'static str = "TSSE";
    // 2.3 only
    pub const TYER_STR: &'static str = "TYER";
    pub const TSST_STR: &'static str = "TSST";
    pub const TXXX_STR: &'static str = "TXXX";
    pub const UFID_STR: &'static str = "UFID";
    pub const USER_STR: &'static str = "USER";
    pub const USLT_STR: &'static str = "USLT";
    pub const WCOM_STR: &'static str = "WCOM";
    pub const WCOP_STR: &'static str = "WCOP";
    pub const WOAF_STR: &'static str = "WOAF";
    pub const WOAR_STR: &'static str = "WOAR";
    pub const WOAS_STR: &'static str = "WOAS";
    pub const WORS_STR: &'static str = "WORS";
    pub const WPAY_STR: &'static str = "WPAY";
    pub const WPUB_STR: &'static str = "WPUB";
    pub const WXXX_STR: &'static str = "WXXX";
}

#[derive(Debug)]
pub enum FrameData {
    AENC(AENC),
    APIC(APIC),
    ASPI(ASPI),
    COMM(COMM),
    COMR(COMR),
    ENCR(ENCR),
    // 2.3 only
    EQUA(EQUA),
    EQU2(EQU2),
    ETCO(ETCO),
    GEOB(GEOB),
    GRID(GRID),
    // 2.3 only
    IPLS(IPLS),
    LINK(LINK),
    MCDI(MCDI),
    MLLT(MLLT),
    OWNE(OWNE),
    PRIV(PRIV),
    PCNT(PCNT),
    POPM(POPM),
    POSS(POSS),
    RBUF(RBUF),
    // 2.3 only
    RVAD(RVA2),
    RVA2(RVA2),
    RVRB(RVRB),
    SEEK(SEEK),
    SIGN(SIGN),
    SYLT(SYLT),
    SYTC(SYTC),
    TALB(TEXT),
    TBPM(TEXT),
    TCOM(TEXT),
    TCON(TEXT),
    TCOP(TEXT),
    // 2.3 only
    TDAT(TEXT),
    TDEN(TEXT),
    TDLY(TEXT),
    TDOR(TEXT),
    TDRC(TEXT),
    TDRL(TEXT),
    TDTG(TEXT),
    TENC(TEXT),
    TEXT(TEXT),
    TFLT(TEXT),
    // 2.3 only
    TIME(TEXT),
    TIPL(TEXT),
    TIT1(TEXT),
    TIT2(TEXT),
    TIT3(TEXT),
    TKEY(TEXT),
    TLAN(TEXT),
    TLEN(TEXT),
    TMCL(TEXT),
    TMED(TEXT),
    TMOO(TEXT),
    TOAL(TEXT),
    TOFN(TEXT),
    TOLY(TEXT),
    TOPE(TEXT),
    TORY(TEXT),
    TOWN(TEXT),
    TPE1(TEXT),
    TPE2(TEXT),
    TPE3(TEXT),
    TPE4(TEXT),
    TPOS(TEXT),
    TPRO(TEXT),
    TPUB(TEXT),
    TRCK(TEXT),
    // 2.3 only
    TRDA(TEXT),
    TRSN(TEXT),
    TRSO(TEXT),
    // 2.3 only
    TSIZ(TEXT),
    TSOA(TEXT),
    TSOP(TEXT),
    TSOT(TEXT),
    TSRC(TEXT),
    TSSE(TEXT),
    // 2.3 only
    TYER(TEXT),
    TSST(TEXT),
    TXXX(TXXX),
    UFID(UFID),
    USER(USER),
    USLT(USLT),
    WCOM(LINK),
    WCOP(LINK),
    WOAF(LINK),
    WOAR(LINK),
    WOAS(LINK),
    WORS(LINK),
    WPAY(LINK),
    WPUB(LINK),
    WXXX(WXXX)
}

#[derive(Debug, PartialEq)]
pub enum PictureType {
    Other,
    FileIcon,
    OtherFileIcon,
    CoverFront,
    CoverBack,
    LeafletPage,
    Media,
    LeadArtist,
    Artist,
    Conductor,
    Band,
    Composer,
    Lyricist,
    RecordingLocation,
    DuringRecording,
    DuringPerformance,
    MovieScreenCapture,
    BrightColouredFish,
    Illustration,
    BandLogotype,
    PublisherLogoType
}

#[derive(Debug, PartialEq)]
pub enum ReceivedAs {
    Other,
    StandardCDAlbum,
    CompressedAudioOnCD,
    FileOverInternet,
    StreamOverInternet,
    AsNoteSheets,
    AsNoteSheetsInBook,
    MusicOnMedia,
    NonMusicalMerchandise
}

#[derive(Debug)]
pub enum InterpolationMethod {
    Band,
    Linear
}

#[derive(Debug, PartialEq)]
pub enum ContentType {
    Other,
    Lyrics,
    TextTranscription,
    MovementName,
    Events,
    Chord,
    Trivia,
    UrlsToWebpages,
    UrlsToImages
}

#[derive(Debug, PartialEq)]
pub enum TimestampFormat {
    MpecFrames,
    Milliseconds
}

#[derive(Debug)]
pub enum EventTimingCode {
    Padding(u32),
    EndOfInitialSilence(u32),
    IntroStart(u32),
    MainPartStart(u32),
    OutroStart(u32),
    OutroEnd(u32),
    VerseStart(u32),
    RefrainStart(u32),
    InterludeStart(u32),
    ThemeStart(u32),
    VariationStart(u32),
    KeyChange(u32),
    TimeChange(u32),
    MomentaryUnwantedNoise(u32),
    SustainedNoise(u32),
    SustainedNoiseEnd(u32),
    IntroEnd(u32),
    MainPartEnd(u32),
    VerseEnd(u32),
    RefrainEnd(u32),
    ThemeEnd(u32),
    Profanity(u32),
    ProfanityEnd(u32),
    ReservedForFutureUse(u32),
    NotPredefinedSynch(u32),
    AudioEnd(u32),
    AudioFileEnds(u32),
    OneMoreByteOfEventsFollows(u32)
}

#[derive(Debug, PartialEq)]
pub enum FrameHeaderFlag {
    TagAlter,
    FileAlter,
    ReadOnly,
    Compression,
    Encryption,
    GroupIdentity,
    //2.4 only
    Unsynchronisation,
    //2.4 only
    DataLength
}<commit_msg>add license text to frame_constants<commit_after>//MIT License
//
//Copyright (c) [2017] [Mark Han]
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.

use id3v2::tag::frame::*;

pub mod id {
    pub const AENC_STR: &'static str = "AENC";
    pub const APIC_STR: &'static str = "APIC";
    pub const ASPI_STR: &'static str = "ASPI";
    pub const COMM_STR: &'static str = "COMM";
    pub const COMR_STR: &'static str = "COMR";
    pub const ENCR_STR: &'static str = "ENCR";
    pub const EQU2_STR: &'static str = "EQU2";
    // 2.3 only
    pub const EQUA_STR: &'static str = "EQUA";
    pub const ETCO_STR: &'static str = "ETCO";
    pub const GEOB_STR: &'static str = "GEOB";
    pub const GRID_STR: &'static str = "GRID";
    // 2.3 only
    pub const IPLS_STR: &'static str = "IPLS";
    pub const LINK_STR: &'static str = "LINK";
    pub const MCDI_STR: &'static str = "MCDI";
    pub const MLLT_STR: &'static str = "MLLT";
    pub const OWNE_STR: &'static str = "OWNE";
    pub const PRIV_STR: &'static str = "PRIV";
    pub const PCNT_STR: &'static str = "PCNT";
    pub const POPM_STR: &'static str = "POPM";
    pub const POSS_STR: &'static str = "POSS";
    pub const RBUF_STR: &'static str = "RBUF";
    // 2.3 only
    pub const RVAD_STR: &'static str = "RVAD";
    pub const RVA2_STR: &'static str = "RVA2";
    pub const RVRB_STR: &'static str = "RVRB";
    pub const SEEK_STR: &'static str = "SEEK";
    pub const SIGN_STR: &'static str = "SIGN";
    pub const SYLT_STR: &'static str = "SYLT";
    pub const SYTC_STR: &'static str = "SYTC";
    pub const TALB_STR: &'static str = "TALB";
    pub const TBPM_STR: &'static str = "TBPM";
    pub const TCOM_STR: &'static str = "TCOM";
    pub const TCON_STR: &'static str = "TCON";
    pub const TCOP_STR: &'static str = "TCOP";
    // 2.3 only
    pub const TDAT_STR: &'static str = "TDAT";
    pub const TDEN_STR: &'static str = "TDEN";
    pub const TDLY_STR: &'static str = "TDLY";
    pub const TDOR_STR: &'static str = "TDOR";
    pub const TDRC_STR: &'static str = "TDRC";
    pub const TDTG_STR: &'static str = "TDTG";
    pub const TDRL_STR: &'static str = "TDRL";
    pub const TENC_STR: &'static str = "TENC";
    pub const TEXT_STR: &'static str = "TEXT";
    pub const TFLT_STR: &'static str = "TFLT";
    // 2.3 only
    pub const TIME_STR: &'static str = "TIME";
    pub const TIPL_STR: &'static str = "TIPL";
    pub const TIT1_STR: &'static str = "TIT1";
    pub const TIT2_STR: &'static str = "TIT2";
    pub const TIT3_STR: &'static str = "TIT3";
    pub const TKEY_STR: &'static str = "TKEY";
    pub const TLAN_STR: &'static str = "TLAN";
    pub const TLEN_STR: &'static str = "TLEN";
    pub const TMCL_STR: &'static str = "TMCL";
    pub const TMED_STR: &'static str = "TMED";
    pub const TMOO_STR: &'static str = "TMOO";
    pub const TOAL_STR: &'static str = "TOAL";
    pub const TOFN_STR: &'static str = "TOFN";
    pub const TOLY_STR: &'static str = "TOLY";
    pub const TOPE_STR: &'static str = "TOPE";
    pub const TORY_STR: &'static str = "TORY";
    pub const TOWN_STR: &'static str = "TOWN";
    pub const TPE1_STR: &'static str = "TPE1";
    pub const TPE2_STR: &'static str = "TPE2";
    pub const TPE3_STR: &'static str = "TPE3";
    pub const TPE4_STR: &'static str = "TPE4";
    pub const TPOS_STR: &'static str = "TPOS";
    pub const TPRO_STR: &'static str = "TPRO";
    pub const TPUB_STR: &'static str = "TPUB";
    pub const TRCK_STR: &'static str = "TRCK";
    pub const TRDA_STR: &'static str = "TRDA";
    pub const TRSN_STR: &'static str = "TRSN";
    pub const TRSO_STR: &'static str = "TRSO";
    // 2.3 only
    pub const TSIZ_STR: &'static str = "TSIZ";
    pub const TSOA_STR: &'static str = "TSOA";
    pub const TSOP_STR: &'static str = "TSOP";
    pub const TSOT_STR: &'static str = "TSOT";
    pub const TSRC_STR: &'static str = "TSRC";
    pub const TSSE_STR: &'static str = "TSSE";
    // 2.3 only
    pub const TYER_STR: &'static str = "TYER";
    pub const TSST_STR: &'static str = "TSST";
    pub const TXXX_STR: &'static str = "TXXX";
    pub const UFID_STR: &'static str = "UFID";
    pub const USER_STR: &'static str = "USER";
    pub const USLT_STR: &'static str = "USLT";
    pub const WCOM_STR: &'static str = "WCOM";
    pub const WCOP_STR: &'static str = "WCOP";
    pub const WOAF_STR: &'static str = "WOAF";
    pub const WOAR_STR: &'static str = "WOAR";
    pub const WOAS_STR: &'static str = "WOAS";
    pub const WORS_STR: &'static str = "WORS";
    pub const WPAY_STR: &'static str = "WPAY";
    pub const WPUB_STR: &'static str = "WPUB";
    pub const WXXX_STR: &'static str = "WXXX";
}

#[derive(Debug)]
pub enum FrameData {
    AENC(AENC),
    APIC(APIC),
    ASPI(ASPI),
    COMM(COMM),
    COMR(COMR),
    ENCR(ENCR),
    // 2.3 only
    EQUA(EQUA),
    EQU2(EQU2),
    ETCO(ETCO),
    GEOB(GEOB),
    GRID(GRID),
    // 2.3 only
    IPLS(IPLS),
    LINK(LINK),
    MCDI(MCDI),
    MLLT(MLLT),
    OWNE(OWNE),
    PRIV(PRIV),
    PCNT(PCNT),
    POPM(POPM),
    POSS(POSS),
    RBUF(RBUF),
    // 2.3 only
    RVAD(RVA2),
    RVA2(RVA2),
    RVRB(RVRB),
    SEEK(SEEK),
    SIGN(SIGN),
    SYLT(SYLT),
    SYTC(SYTC),
    TALB(TEXT),
    TBPM(TEXT),
    TCOM(TEXT),
    TCON(TEXT),
    TCOP(TEXT),
    // 2.3 only
    TDAT(TEXT),
    TDEN(TEXT),
    TDLY(TEXT),
    TDOR(TEXT),
    TDRC(TEXT),
    TDRL(TEXT),
    TDTG(TEXT),
    TENC(TEXT),
    TEXT(TEXT),
    TFLT(TEXT),
    // 2.3 only
    TIME(TEXT),
    TIPL(TEXT),
    TIT1(TEXT),
    TIT2(TEXT),
    TIT3(TEXT),
    TKEY(TEXT),
    TLAN(TEXT),
    TLEN(TEXT),
    TMCL(TEXT),
    TMED(TEXT),
    TMOO(TEXT),
    TOAL(TEXT),
    TOFN(TEXT),
    TOLY(TEXT),
    TOPE(TEXT),
    TORY(TEXT),
    TOWN(TEXT),
    TPE1(TEXT),
    TPE2(TEXT),
    TPE3(TEXT),
    TPE4(TEXT),
    TPOS(TEXT),
    TPRO(TEXT),
    TPUB(TEXT),
    TRCK(TEXT),
    // 2.3 only
    TRDA(TEXT),
    TRSN(TEXT),
    TRSO(TEXT),
    // 2.3 only
    TSIZ(TEXT),
    TSOA(TEXT),
    TSOP(TEXT),
    TSOT(TEXT),
    TSRC(TEXT),
    TSSE(TEXT),
    // 2.3 only
    TYER(TEXT),
    TSST(TEXT),
    TXXX(TXXX),
    UFID(UFID),
    USER(USER),
    USLT(USLT),
    WCOM(LINK),
    WCOP(LINK),
    WOAF(LINK),
    WOAR(LINK),
    WOAS(LINK),
    WORS(LINK),
    WPAY(LINK),
    WPUB(LINK),
    WXXX(WXXX)
}

#[derive(Debug, PartialEq)]
pub enum PictureType {
    Other,
    FileIcon,
    OtherFileIcon,
    CoverFront,
    CoverBack,
    LeafletPage,
    Media,
    LeadArtist,
    Artist,
    Conductor,
    Band,
    Composer,
    Lyricist,
    RecordingLocation,
    DuringRecording,
    DuringPerformance,
    MovieScreenCapture,
    BrightColouredFish,
    Illustration,
    BandLogotype,
    PublisherLogoType
}

#[derive(Debug, PartialEq)]
pub enum ReceivedAs {
    Other,
    StandardCDAlbum,
    CompressedAudioOnCD,
    FileOverInternet,
    StreamOverInternet,
    AsNoteSheets,
    AsNoteSheetsInBook,
    MusicOnMedia,
    NonMusicalMerchandise
}

#[derive(Debug)]
pub enum InterpolationMethod {
    Band,
    Linear
}

#[derive(Debug, PartialEq)]
pub enum ContentType {
    Other,
    Lyrics,
    TextTranscription,
    MovementName,
    Events,
    Chord,
    Trivia,
    UrlsToWebpages,
    UrlsToImages
}

#[derive(Debug, PartialEq)]
pub enum TimestampFormat {
    MpecFrames,
    Milliseconds
}

#[derive(Debug)]
pub enum EventTimingCode {
    Padding(u32),
    EndOfInitialSilence(u32),
    IntroStart(u32),
    MainPartStart(u32),
    OutroStart(u32),
    OutroEnd(u32),
    VerseStart(u32),
    RefrainStart(u32),
    InterludeStart(u32),
    ThemeStart(u32),
    VariationStart(u32),
    KeyChange(u32),
    TimeChange(u32),
    MomentaryUnwantedNoise(u32),
    SustainedNoise(u32),
    SustainedNoiseEnd(u32),
    IntroEnd(u32),
    MainPartEnd(u32),
    VerseEnd(u32),
    RefrainEnd(u32),
    ThemeEnd(u32),
    Profanity(u32),
    ProfanityEnd(u32),
    ReservedForFutureUse(u32),
    NotPredefinedSynch(u32),
    AudioEnd(u32),
    AudioFileEnds(u32),
    OneMoreByteOfEventsFollows(u32)
}

#[derive(Debug, PartialEq)]
pub enum FrameHeaderFlag {
    TagAlter,
    FileAlter,
    ReadOnly,
    Compression,
    Encryption,
    GroupIdentity,
    //2.4 only
    Unsynchronisation,
    //2.4 only
    DataLength
}<|endoftext|>


<commit_before>#!/usr/bin/env rustx
// pp-exact

use io::println;

fn main() { io::println(~"Hello World"); }
<commit_msg>Remove 'use' line that's confusing pp-exact during use/import transition.<commit_after>#!/usr/bin/env rustx
// pp-exact

fn main() { io::println("Hello World"); }
<|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/. */

//! A wrapper over an element and a snapshot, that allows us to selector-match
//! against a past state of the element.

use {Atom, CaseSensitivityExt, LocalName, Namespace};
use dom::TElement;
use element_state::ElementState;
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
use selectors::{Element, OpaqueElement};
use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
use selectors::matching::{ElementSelectorFlags, MatchingContext};
use selectors::matching::RelevantLinkStatus;
use std::cell::Cell;
use std::fmt;

/// In order to compute restyle hints, we perform a selector match against a
/// list of partial selectors whose rightmost simple selector may be sensitive
/// to the thing being changed. We do this matching twice, once for the element
/// as it exists now and once for the element as it existed at the time of the
/// last restyle. If the results of the selector match differ, that means that
/// the given partial selector is sensitive to the change, and we compute a
/// restyle hint based on its combinator.
///
/// In order to run selector matching against the old element state, we generate
/// a wrapper for the element which claims to have the old state. This is the
/// ElementWrapper logic below.
///
/// Gecko does this differently for element states, and passes a mask called
/// mStateMask, which indicates the states that need to be ignored during
/// selector matching. This saves an ElementWrapper allocation and an additional
/// selector match call at the expense of additional complexity inside the
/// selector matching logic. This only works for boolean states though, so we
/// still need to take the ElementWrapper approach for attribute-dependent
/// style. So we do it the same both ways for now to reduce complexity, but it's
/// worth measuring the performance impact (if any) of the mStateMask approach.
pub trait ElementSnapshot : Sized {
    /// The state of the snapshot, if any.
    fn state(&self) -> Option<ElementState>;

    /// If this snapshot contains attribute information.
    fn has_attrs(&self) -> bool;

    /// The ID attribute per this snapshot. Should only be called if
    /// `has_attrs()` returns true.
    fn id_attr(&self) -> Option<Atom>;

    /// Whether this snapshot contains the class `name`. Should only be called
    /// if `has_attrs()` returns true.
    fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool;

    /// A callback that should be called for each class of the snapshot. Should
    /// only be called if `has_attrs()` returns true.
    fn each_class<F>(&self, F)
        where F: FnMut(&Atom);

    /// The `xml:lang=""` or `lang=""` attribute value per this snapshot.
    fn lang_attr(&self) -> Option<AttrValue>;
}

/// A simple wrapper over an element and a snapshot, that allows us to
/// selector-match against a past state of the element.
#[derive(Clone)]
pub struct ElementWrapper<'a, E>
    where E: TElement,
{
    element: E,
    cached_snapshot: Cell<Option<&'a Snapshot>>,
    snapshot_map: &'a SnapshotMap,
}

impl<'a, E> ElementWrapper<'a, E>
    where E: TElement,
{
    /// Trivially constructs an `ElementWrapper`.
    pub fn new(el: E, snapshot_map: &'a SnapshotMap) -> Self {
        ElementWrapper {
            element: el,
            cached_snapshot: Cell::new(None),
            snapshot_map: snapshot_map,
        }
    }

    /// Gets the snapshot associated with this element, if any.
    pub fn snapshot(&self) -> Option<&'a Snapshot> {
        if !self.element.has_snapshot() {
            return None;
        }

        if let Some(s) = self.cached_snapshot.get() {
            return Some(s);
        }

        let snapshot = self.snapshot_map.get(&self.element);
        debug_assert!(snapshot.is_some(), "has_snapshot lied!");

        self.cached_snapshot.set(snapshot);

        snapshot
    }

    /// Returns the states that have changed since the element was snapshotted.
    pub fn state_changes(&self) -> ElementState {
        let snapshot = match self.snapshot() {
            Some(s) => s,
            None => return ElementState::empty(),
        };

        match snapshot.state() {
            Some(state) => state ^ self.element.get_state(),
            None => ElementState::empty(),
        }
    }

    /// Returns the value of the `xml:lang=""` (or, if appropriate, `lang=""`)
    /// attribute from this element's snapshot or the closest ancestor
    /// element snapshot with the attribute specified.
    fn get_lang(&self) -> Option<AttrValue> {
        let mut current = self.clone();
        loop {
            let lang = match self.snapshot() {
                Some(snapshot) if snapshot.has_attrs() => snapshot.lang_attr(),
                _ => current.element.lang_attr(),
            };
            if lang.is_some() {
                return lang;
            }
            match current.parent_element() {
                Some(parent) => current = parent,
                None => return None,
            }
        }
    }
}

impl<'a, E> fmt::Debug for ElementWrapper<'a, E>
    where E: TElement,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Ignore other fields for now, can change later if needed.
        self.element.fmt(f)
    }
}

impl<'a, E> Element for ElementWrapper<'a, E>
    where E: TElement,
{
    type Impl = SelectorImpl;

    fn match_non_ts_pseudo_class<F>(
        &self,
        pseudo_class: &NonTSPseudoClass,
        context: &mut MatchingContext,
        relevant_link: &RelevantLinkStatus,
        _setter: &mut F,
    ) -> bool
    where
         F: FnMut(&Self, ElementSelectorFlags),
    {
        // Some pseudo-classes need special handling to evaluate them against
        // the snapshot.
        match *pseudo_class {
            #[cfg(feature = "gecko")]
            NonTSPseudoClass::MozAny(ref selectors) => {
                use selectors::matching::matches_complex_selector;
                // FIXME(emilio): nesting_level!
                return selectors.iter().any(|s| {
                    matches_complex_selector(s.iter(), self, context, _setter)
                })
            }

            // :dir is implemented in terms of state flags, but which state flag
            // it maps to depends on the argument to :dir.  That means we can't
            // just add its state flags to the NonTSPseudoClass, because if we
            // added all of them there, and tested via intersects() here, we'd
            // get incorrect behavior for :not(:dir()) cases.
            //
            // FIXME(bz): How can I set this up so once Servo adds :dir()
            // support we don't forget to update this code?
            #[cfg(feature = "gecko")]
            NonTSPseudoClass::Dir(ref s) => {
                use invalidation::element::invalidation_map::dir_selector_to_state;
                let selector_flag = dir_selector_to_state(s);
                if selector_flag.is_empty() {
                    // :dir() with some random argument; does not match.
                    return false;
                }
                let state = match self.snapshot().and_then(|s| s.state()) {
                    Some(snapshot_state) => snapshot_state,
                    None => self.element.get_state(),
                };
                return state.contains(selector_flag);
            }

            // For :link and :visited, we don't actually want to test the element
            // state directly.  Instead, we use the `relevant_link` to determine if
            // they match.
            NonTSPseudoClass::Link => {
                return relevant_link.is_unvisited(self, context);
            }
            NonTSPseudoClass::Visited => {
                return relevant_link.is_visited(self, context);
            }

            #[cfg(feature = "gecko")]
            NonTSPseudoClass::MozTableBorderNonzero => {
                if let Some(snapshot) = self.snapshot() {
                    if snapshot.has_other_pseudo_class_state() {
                        return snapshot.mIsTableBorderNonzero();
                    }
                }
            }

            #[cfg(feature = "gecko")]
            NonTSPseudoClass::MozBrowserFrame => {
                if let Some(snapshot) = self.snapshot() {
                    if snapshot.has_other_pseudo_class_state() {
                        return snapshot.mIsMozBrowserFrame();
                    }
                }
            }

            // :lang() needs to match using the closest ancestor xml:lang="" or
            // lang="" attribtue from snapshots.
            NonTSPseudoClass::Lang(ref lang_arg) => {
                return self.element.match_element_lang(Some(self.get_lang()), lang_arg);
            }

            _ => {}
        }

        let flag = pseudo_class.state_flag();
        if flag.is_empty() {
            return self.element.match_non_ts_pseudo_class(
                pseudo_class,
                context,
                relevant_link,
                &mut |_, _| {},
            )
        }
        match self.snapshot().and_then(|s| s.state()) {
            Some(snapshot_state) => snapshot_state.intersects(flag),
            None => {
                self.element.match_non_ts_pseudo_class(
                    pseudo_class,
                    context,
                    relevant_link,
                    &mut |_, _| {},
                )
            }
        }
    }

    fn match_pseudo_element(
        &self,
        pseudo_element: &PseudoElement,
        context: &mut MatchingContext,
    ) -> bool {
        self.element.match_pseudo_element(pseudo_element, context)
    }

    fn is_link(&self) -> bool {
        self.element.is_link()
    }

    fn opaque(&self) -> OpaqueElement {
        self.element.opaque()
    }

    fn parent_element(&self) -> Option<Self> {
        self.element.parent_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn first_child_element(&self) -> Option<Self> {
        self.element.first_child_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn last_child_element(&self) -> Option<Self> {
        self.element.last_child_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn prev_sibling_element(&self) -> Option<Self> {
        self.element.prev_sibling_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn next_sibling_element(&self) -> Option<Self> {
        self.element.next_sibling_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn is_html_element_in_html_document(&self) -> bool {
        self.element.is_html_element_in_html_document()
    }

    fn get_local_name(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedLocalName {
        self.element.get_local_name()
    }

    fn get_namespace(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedNamespaceUrl {
        self.element.get_namespace()
    }

    fn attr_matches(&self,
                    ns: &NamespaceConstraint<&Namespace>,
                    local_name: &LocalName,
                    operation: &AttrSelectorOperation<&AttrValue>)
                    -> bool {
        match self.snapshot() {
            Some(snapshot) if snapshot.has_attrs() => {
                snapshot.attr_matches(ns, local_name, operation)
            }
            _ => self.element.attr_matches(ns, local_name, operation)
        }
    }

    fn has_id(&self, id: &Atom, case_sensitivity: CaseSensitivity) -> bool {
        match self.snapshot() {
            Some(snapshot) if snapshot.has_attrs() => {
                snapshot.id_attr().map_or(false, |atom| case_sensitivity.eq_atom(&atom, id))
            }
            _ => self.element.has_id(id, case_sensitivity)
        }
    }

    fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
        match self.snapshot() {
            Some(snapshot) if snapshot.has_attrs() => {
                snapshot.has_class(name, case_sensitivity)
            }
            _ => self.element.has_class(name, case_sensitivity)
        }
    }

    fn is_empty(&self) -> bool {
        self.element.is_empty()
    }

    fn is_root(&self) -> bool {
        self.element.is_root()
    }

    fn pseudo_element_originating_element(&self) -> Option<Self> {
        self.element.closest_non_native_anonymous_ancestor()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }
}
<commit_msg>style: Properly use nesting_level in the invalidation code.<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/. */

//! A wrapper over an element and a snapshot, that allows us to selector-match
//! against a past state of the element.

use {Atom, CaseSensitivityExt, LocalName, Namespace};
use dom::TElement;
use element_state::ElementState;
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
use selectors::{Element, OpaqueElement};
use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
use selectors::matching::{ElementSelectorFlags, MatchingContext};
use selectors::matching::RelevantLinkStatus;
use std::cell::Cell;
use std::fmt;

/// In order to compute restyle hints, we perform a selector match against a
/// list of partial selectors whose rightmost simple selector may be sensitive
/// to the thing being changed. We do this matching twice, once for the element
/// as it exists now and once for the element as it existed at the time of the
/// last restyle. If the results of the selector match differ, that means that
/// the given partial selector is sensitive to the change, and we compute a
/// restyle hint based on its combinator.
///
/// In order to run selector matching against the old element state, we generate
/// a wrapper for the element which claims to have the old state. This is the
/// ElementWrapper logic below.
///
/// Gecko does this differently for element states, and passes a mask called
/// mStateMask, which indicates the states that need to be ignored during
/// selector matching. This saves an ElementWrapper allocation and an additional
/// selector match call at the expense of additional complexity inside the
/// selector matching logic. This only works for boolean states though, so we
/// still need to take the ElementWrapper approach for attribute-dependent
/// style. So we do it the same both ways for now to reduce complexity, but it's
/// worth measuring the performance impact (if any) of the mStateMask approach.
pub trait ElementSnapshot : Sized {
    /// The state of the snapshot, if any.
    fn state(&self) -> Option<ElementState>;

    /// If this snapshot contains attribute information.
    fn has_attrs(&self) -> bool;

    /// The ID attribute per this snapshot. Should only be called if
    /// `has_attrs()` returns true.
    fn id_attr(&self) -> Option<Atom>;

    /// Whether this snapshot contains the class `name`. Should only be called
    /// if `has_attrs()` returns true.
    fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool;

    /// A callback that should be called for each class of the snapshot. Should
    /// only be called if `has_attrs()` returns true.
    fn each_class<F>(&self, F)
        where F: FnMut(&Atom);

    /// The `xml:lang=""` or `lang=""` attribute value per this snapshot.
    fn lang_attr(&self) -> Option<AttrValue>;
}

/// A simple wrapper over an element and a snapshot, that allows us to
/// selector-match against a past state of the element.
#[derive(Clone)]
pub struct ElementWrapper<'a, E>
    where E: TElement,
{
    element: E,
    cached_snapshot: Cell<Option<&'a Snapshot>>,
    snapshot_map: &'a SnapshotMap,
}

impl<'a, E> ElementWrapper<'a, E>
    where E: TElement,
{
    /// Trivially constructs an `ElementWrapper`.
    pub fn new(el: E, snapshot_map: &'a SnapshotMap) -> Self {
        ElementWrapper {
            element: el,
            cached_snapshot: Cell::new(None),
            snapshot_map: snapshot_map,
        }
    }

    /// Gets the snapshot associated with this element, if any.
    pub fn snapshot(&self) -> Option<&'a Snapshot> {
        if !self.element.has_snapshot() {
            return None;
        }

        if let Some(s) = self.cached_snapshot.get() {
            return Some(s);
        }

        let snapshot = self.snapshot_map.get(&self.element);
        debug_assert!(snapshot.is_some(), "has_snapshot lied!");

        self.cached_snapshot.set(snapshot);

        snapshot
    }

    /// Returns the states that have changed since the element was snapshotted.
    pub fn state_changes(&self) -> ElementState {
        let snapshot = match self.snapshot() {
            Some(s) => s,
            None => return ElementState::empty(),
        };

        match snapshot.state() {
            Some(state) => state ^ self.element.get_state(),
            None => ElementState::empty(),
        }
    }

    /// Returns the value of the `xml:lang=""` (or, if appropriate, `lang=""`)
    /// attribute from this element's snapshot or the closest ancestor
    /// element snapshot with the attribute specified.
    fn get_lang(&self) -> Option<AttrValue> {
        let mut current = self.clone();
        loop {
            let lang = match self.snapshot() {
                Some(snapshot) if snapshot.has_attrs() => snapshot.lang_attr(),
                _ => current.element.lang_attr(),
            };
            if lang.is_some() {
                return lang;
            }
            match current.parent_element() {
                Some(parent) => current = parent,
                None => return None,
            }
        }
    }
}

impl<'a, E> fmt::Debug for ElementWrapper<'a, E>
    where E: TElement,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Ignore other fields for now, can change later if needed.
        self.element.fmt(f)
    }
}

impl<'a, E> Element for ElementWrapper<'a, E>
    where E: TElement,
{
    type Impl = SelectorImpl;

    fn match_non_ts_pseudo_class<F>(
        &self,
        pseudo_class: &NonTSPseudoClass,
        context: &mut MatchingContext,
        relevant_link: &RelevantLinkStatus,
        _setter: &mut F,
    ) -> bool
    where
         F: FnMut(&Self, ElementSelectorFlags),
    {
        // Some pseudo-classes need special handling to evaluate them against
        // the snapshot.
        match *pseudo_class {
            #[cfg(feature = "gecko")]
            NonTSPseudoClass::MozAny(ref selectors) => {
                use selectors::matching::matches_complex_selector;
                context.nesting_level += 1;
                let result = selectors.iter().any(|s| {
                    matches_complex_selector(s.iter(), self, context, _setter)
                });
                context.nesting_level -= 1;
                return result
            }

            // :dir is implemented in terms of state flags, but which state flag
            // it maps to depends on the argument to :dir.  That means we can't
            // just add its state flags to the NonTSPseudoClass, because if we
            // added all of them there, and tested via intersects() here, we'd
            // get incorrect behavior for :not(:dir()) cases.
            //
            // FIXME(bz): How can I set this up so once Servo adds :dir()
            // support we don't forget to update this code?
            #[cfg(feature = "gecko")]
            NonTSPseudoClass::Dir(ref s) => {
                use invalidation::element::invalidation_map::dir_selector_to_state;
                let selector_flag = dir_selector_to_state(s);
                if selector_flag.is_empty() {
                    // :dir() with some random argument; does not match.
                    return false;
                }
                let state = match self.snapshot().and_then(|s| s.state()) {
                    Some(snapshot_state) => snapshot_state,
                    None => self.element.get_state(),
                };
                return state.contains(selector_flag);
            }

            // For :link and :visited, we don't actually want to test the element
            // state directly.  Instead, we use the `relevant_link` to determine if
            // they match.
            NonTSPseudoClass::Link => {
                return relevant_link.is_unvisited(self, context);
            }
            NonTSPseudoClass::Visited => {
                return relevant_link.is_visited(self, context);
            }

            #[cfg(feature = "gecko")]
            NonTSPseudoClass::MozTableBorderNonzero => {
                if let Some(snapshot) = self.snapshot() {
                    if snapshot.has_other_pseudo_class_state() {
                        return snapshot.mIsTableBorderNonzero();
                    }
                }
            }

            #[cfg(feature = "gecko")]
            NonTSPseudoClass::MozBrowserFrame => {
                if let Some(snapshot) = self.snapshot() {
                    if snapshot.has_other_pseudo_class_state() {
                        return snapshot.mIsMozBrowserFrame();
                    }
                }
            }

            // :lang() needs to match using the closest ancestor xml:lang="" or
            // lang="" attribtue from snapshots.
            NonTSPseudoClass::Lang(ref lang_arg) => {
                return self.element.match_element_lang(Some(self.get_lang()), lang_arg);
            }

            _ => {}
        }

        let flag = pseudo_class.state_flag();
        if flag.is_empty() {
            return self.element.match_non_ts_pseudo_class(
                pseudo_class,
                context,
                relevant_link,
                &mut |_, _| {},
            )
        }
        match self.snapshot().and_then(|s| s.state()) {
            Some(snapshot_state) => snapshot_state.intersects(flag),
            None => {
                self.element.match_non_ts_pseudo_class(
                    pseudo_class,
                    context,
                    relevant_link,
                    &mut |_, _| {},
                )
            }
        }
    }

    fn match_pseudo_element(
        &self,
        pseudo_element: &PseudoElement,
        context: &mut MatchingContext,
    ) -> bool {
        self.element.match_pseudo_element(pseudo_element, context)
    }

    fn is_link(&self) -> bool {
        self.element.is_link()
    }

    fn opaque(&self) -> OpaqueElement {
        self.element.opaque()
    }

    fn parent_element(&self) -> Option<Self> {
        self.element.parent_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn first_child_element(&self) -> Option<Self> {
        self.element.first_child_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn last_child_element(&self) -> Option<Self> {
        self.element.last_child_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn prev_sibling_element(&self) -> Option<Self> {
        self.element.prev_sibling_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn next_sibling_element(&self) -> Option<Self> {
        self.element.next_sibling_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn is_html_element_in_html_document(&self) -> bool {
        self.element.is_html_element_in_html_document()
    }

    fn get_local_name(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedLocalName {
        self.element.get_local_name()
    }

    fn get_namespace(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedNamespaceUrl {
        self.element.get_namespace()
    }

    fn attr_matches(&self,
                    ns: &NamespaceConstraint<&Namespace>,
                    local_name: &LocalName,
                    operation: &AttrSelectorOperation<&AttrValue>)
                    -> bool {
        match self.snapshot() {
            Some(snapshot) if snapshot.has_attrs() => {
                snapshot.attr_matches(ns, local_name, operation)
            }
            _ => self.element.attr_matches(ns, local_name, operation)
        }
    }

    fn has_id(&self, id: &Atom, case_sensitivity: CaseSensitivity) -> bool {
        match self.snapshot() {
            Some(snapshot) if snapshot.has_attrs() => {
                snapshot.id_attr().map_or(false, |atom| case_sensitivity.eq_atom(&atom, id))
            }
            _ => self.element.has_id(id, case_sensitivity)
        }
    }

    fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
        match self.snapshot() {
            Some(snapshot) if snapshot.has_attrs() => {
                snapshot.has_class(name, case_sensitivity)
            }
            _ => self.element.has_class(name, case_sensitivity)
        }
    }

    fn is_empty(&self) -> bool {
        self.element.is_empty()
    }

    fn is_root(&self) -> bool {
        self.element.is_root()
    }

    fn pseudo_element_originating_element(&self) -> Option<Self> {
        self.element.closest_non_native_anonymous_ancestor()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }
}
<|endoftext|>


<commit_before>//! Contains `ParseSess` which holds state living beyond what one `Parser` might.
//! It also serves as an input to the parser itself.

use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId};
use crate::node_id::NodeId;

use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{Lock, Lrc, Once};
use rustc_error_codes::E0658;
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
use rustc_errors::{error_code, Applicability, DiagnosticBuilder};
use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
use rustc_span::edition::Edition;
use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{MultiSpan, Span, Symbol};

use std::path::PathBuf;
use std::str;

/// The set of keys (and, optionally, values) that define the compilation
/// environment of the crate, used to drive conditional compilation.
pub type CrateConfig = FxHashSet<(Symbol, Option<Symbol>)>;

/// Collected spans during parsing for places where a certain feature was
/// used and should be feature gated accordingly in `check_crate`.
#[derive(Default)]
pub struct GatedSpans {
    pub spans: Lock<FxHashMap<Symbol, Vec<Span>>>,
}

impl GatedSpans {
    /// Feature gate the given `span` under the given `feature`
    /// which is same `Symbol` used in `active.rs`.
    pub fn gate(&self, feature: Symbol, span: Span) {
        self.spans.borrow_mut().entry(feature).or_default().push(span);
    }

    /// Ungate the last span under the given `feature`.
    /// Panics if the given `span` wasn't the last one.
    ///
    /// Using this is discouraged unless you have a really good reason to.
    pub fn ungate_last(&self, feature: Symbol, span: Span) {
        let removed_span = self.spans.borrow_mut().entry(feature).or_default().pop().unwrap();
        debug_assert_eq!(span, removed_span);
    }

    /// Is the provided `feature` gate ungated currently?
    ///
    /// Using this is discouraged unless you have a really good reason to.
    pub fn is_ungated(&self, feature: Symbol) -> bool {
        self.spans.borrow().get(&feature).map_or(true, |spans| spans.is_empty())
    }

    /// Prepend the given set of `spans` onto the set in `self`.
    pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) {
        let mut inner = self.spans.borrow_mut();
        for (gate, mut gate_spans) in inner.drain() {
            spans.entry(gate).or_default().append(&mut gate_spans);
        }
        *inner = spans;
    }
}

/// The strenght of a feature gate.
/// Either it is a `Hard` error, or only a `Soft` warning.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum GateStrength {
    /// A hard error. (Most feature gates should use this.)
    Hard,
    /// Only a warning. (Use this only as backwards-compatibility demands.)
    Soft,
}

/// Construct a diagnostic for a language feature error due to the given `span`.
/// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`.
///
/// Example usage:
///
/// ```ignore
/// feature_err(
///     parse_sess,
///     sym::stmt_expr_attributes,
///     attr.span,
///     "attributes on expressions are unstable",
/// )
/// .emit();
/// ```
pub fn feature_err<'a>(
    sess: &'a ParseSess,
    feature: Symbol,
    span: impl Into<MultiSpan>,
    explain: &str,
) -> DiagnosticBuilder<'a> {
    feature_err_issue(sess, feature, span, GateIssue::Language, explain)
}

/// Construct a diagnostic for a feature gate error.
///
/// This variant allows you to control whether it is a library or language feature.
/// Almost always, you want to use this for a language feature. If so, prefer `feature_err`.
pub fn feature_err_issue<'a>(
    sess: &'a ParseSess,
    feature: Symbol,
    span: impl Into<MultiSpan>,
    issue: GateIssue,
    explain: &str,
) -> DiagnosticBuilder<'a> {
    leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
}

/// Construct a diagnostic for a feature gate error / warning.
///
/// You should typically just use `feature_err` instead.
pub fn leveled_feature_err<'a>(
    sess: &'a ParseSess,
    feature: Symbol,
    span: impl Into<MultiSpan>,
    issue: GateIssue,
    explain: &str,
    level: GateStrength,
) -> DiagnosticBuilder<'a> {
    let diag = &sess.span_diagnostic;

    let mut err = match level {
        GateStrength::Hard => diag.struct_span_err_with_code(span, explain, error_code!(E0658)),
        GateStrength::Soft => diag.struct_span_warn(span, explain),
    };

    if let Some(n) = find_feature_issue(feature, issue) {
        err.note(&format!(
            "for more information, see https://github.com/rust-lang/rust/issues/{}",
            n,
        ));
    }

    // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
    if sess.unstable_features.is_nightly_build() {
        err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
    }

    // If we're on stable and only emitting a "soft" warning, add a note to
    // clarify that the feature isn't "on" (rather than being on but
    // warning-worthy).
    if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft {
        err.help("a nightly build of the compiler is required to enable this feature");
    }

    err
}

/// Info about a parsing session.
pub struct ParseSess {
    pub span_diagnostic: Handler,
    pub unstable_features: UnstableFeatures,
    pub config: CrateConfig,
    pub edition: Edition,
    pub missing_fragment_specifiers: Lock<FxHashSet<Span>>,
    /// Places where raw identifiers were used. This is used for feature-gating raw identifiers.
    pub raw_identifier_spans: Lock<Vec<Span>>,
    /// Used to determine and report recursive module inclusions.
    pub included_mod_stack: Lock<Vec<PathBuf>>,
    source_map: Lrc<SourceMap>,
    pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
    /// Contains the spans of block expressions that could have been incomplete based on the
    /// operation token that followed it, but that the parser cannot identify without further
    /// analysis.
    pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
    pub injected_crate_name: Once<Symbol>,
    pub gated_spans: GatedSpans,
    /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
    pub reached_eof: Lock<bool>,
}

impl ParseSess {
    pub fn new(file_path_mapping: FilePathMapping) -> Self {
        let cm = Lrc::new(SourceMap::new(file_path_mapping));
        let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, None, Some(cm.clone()));
        ParseSess::with_span_handler(handler, cm)
    }

    pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self {
        Self {
            span_diagnostic: handler,
            unstable_features: UnstableFeatures::from_environment(),
            config: FxHashSet::default(),
            edition: ExpnId::root().expn_data().edition,
            missing_fragment_specifiers: Lock::new(FxHashSet::default()),
            raw_identifier_spans: Lock::new(Vec::new()),
            included_mod_stack: Lock::new(vec![]),
            source_map,
            buffered_lints: Lock::new(vec![]),
            ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
            injected_crate_name: Once::new(),
            gated_spans: GatedSpans::default(),
            reached_eof: Lock::new(false),
        }
    }

    pub fn with_silent_emitter() -> Self {
        let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
        let handler = Handler::with_emitter(false, None, Box::new(SilentEmitter));
        ParseSess::with_span_handler(handler, cm)
    }

    #[inline]
    pub fn source_map(&self) -> &SourceMap {
        &self.source_map
    }

    pub fn buffer_lint(
        &self,
        lint: &'static Lint,
        span: impl Into<MultiSpan>,
        node_id: NodeId,
        msg: &str,
    ) {
        self.buffered_lints.with_lock(|buffered_lints| {
            buffered_lints.push(BufferedEarlyLint {
                span: span.into(),
                node_id,
                msg: msg.into(),
                lint_id: LintId::of(lint),
                diagnostic: BuiltinLintDiagnostics::Normal,
            });
        });
    }

    /// Extend an error with a suggestion to wrap an expression with parentheses to allow the
    /// parser to continue parsing the following operation as part of the same expression.
    pub fn expr_parentheses_needed(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        span: Span,
        alt_snippet: Option<String>,
    ) {
        if let Some(snippet) = self.source_map().span_to_snippet(span).ok().or(alt_snippet) {
            err.span_suggestion(
                span,
                "parentheses are required to parse this as an expression",
                format!("({})", snippet),
                Applicability::MachineApplicable,
            );
        }
    }
}
<commit_msg>pacify tidy by nixing added docs :(<commit_after>//! Contains `ParseSess` which holds state living beyond what one `Parser` might.
//! It also serves as an input to the parser itself.

use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId};
use crate::node_id::NodeId;

use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{Lock, Lrc, Once};
use rustc_error_codes::E0658;
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
use rustc_errors::{error_code, Applicability, DiagnosticBuilder};
use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
use rustc_span::edition::Edition;
use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{MultiSpan, Span, Symbol};

use std::path::PathBuf;
use std::str;

/// The set of keys (and, optionally, values) that define the compilation
/// environment of the crate, used to drive conditional compilation.
pub type CrateConfig = FxHashSet<(Symbol, Option<Symbol>)>;

/// Collected spans during parsing for places where a certain feature was
/// used and should be feature gated accordingly in `check_crate`.
#[derive(Default)]
pub struct GatedSpans {
    pub spans: Lock<FxHashMap<Symbol, Vec<Span>>>,
}

impl GatedSpans {
    /// Feature gate the given `span` under the given `feature`
    /// which is same `Symbol` used in `active.rs`.
    pub fn gate(&self, feature: Symbol, span: Span) {
        self.spans.borrow_mut().entry(feature).or_default().push(span);
    }

    /// Ungate the last span under the given `feature`.
    /// Panics if the given `span` wasn't the last one.
    ///
    /// Using this is discouraged unless you have a really good reason to.
    pub fn ungate_last(&self, feature: Symbol, span: Span) {
        let removed_span = self.spans.borrow_mut().entry(feature).or_default().pop().unwrap();
        debug_assert_eq!(span, removed_span);
    }

    /// Is the provided `feature` gate ungated currently?
    ///
    /// Using this is discouraged unless you have a really good reason to.
    pub fn is_ungated(&self, feature: Symbol) -> bool {
        self.spans.borrow().get(&feature).map_or(true, |spans| spans.is_empty())
    }

    /// Prepend the given set of `spans` onto the set in `self`.
    pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) {
        let mut inner = self.spans.borrow_mut();
        for (gate, mut gate_spans) in inner.drain() {
            spans.entry(gate).or_default().append(&mut gate_spans);
        }
        *inner = spans;
    }
}

/// The strenght of a feature gate.
/// Either it is a `Hard` error, or only a `Soft` warning.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum GateStrength {
    /// A hard error. (Most feature gates should use this.)
    Hard,
    /// Only a warning. (Use this only as backwards-compatibility demands.)
    Soft,
}

/// Construct a diagnostic for a language feature error due to the given `span`.
/// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`.
pub fn feature_err<'a>(
    sess: &'a ParseSess,
    feature: Symbol,
    span: impl Into<MultiSpan>,
    explain: &str,
) -> DiagnosticBuilder<'a> {
    feature_err_issue(sess, feature, span, GateIssue::Language, explain)
}

/// Construct a diagnostic for a feature gate error.
///
/// This variant allows you to control whether it is a library or language feature.
/// Almost always, you want to use this for a language feature. If so, prefer `feature_err`.
pub fn feature_err_issue<'a>(
    sess: &'a ParseSess,
    feature: Symbol,
    span: impl Into<MultiSpan>,
    issue: GateIssue,
    explain: &str,
) -> DiagnosticBuilder<'a> {
    leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
}

/// Construct a diagnostic for a feature gate error / warning.
///
/// You should typically just use `feature_err` instead.
pub fn leveled_feature_err<'a>(
    sess: &'a ParseSess,
    feature: Symbol,
    span: impl Into<MultiSpan>,
    issue: GateIssue,
    explain: &str,
    level: GateStrength,
) -> DiagnosticBuilder<'a> {
    let diag = &sess.span_diagnostic;

    let mut err = match level {
        GateStrength::Hard => diag.struct_span_err_with_code(span, explain, error_code!(E0658)),
        GateStrength::Soft => diag.struct_span_warn(span, explain),
    };

    if let Some(n) = find_feature_issue(feature, issue) {
        err.note(&format!(
            "for more information, see https://github.com/rust-lang/rust/issues/{}",
            n,
        ));
    }

    // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
    if sess.unstable_features.is_nightly_build() {
        err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
    }

    // If we're on stable and only emitting a "soft" warning, add a note to
    // clarify that the feature isn't "on" (rather than being on but
    // warning-worthy).
    if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft {
        err.help("a nightly build of the compiler is required to enable this feature");
    }

    err
}

/// Info about a parsing session.
pub struct ParseSess {
    pub span_diagnostic: Handler,
    pub unstable_features: UnstableFeatures,
    pub config: CrateConfig,
    pub edition: Edition,
    pub missing_fragment_specifiers: Lock<FxHashSet<Span>>,
    /// Places where raw identifiers were used. This is used for feature-gating raw identifiers.
    pub raw_identifier_spans: Lock<Vec<Span>>,
    /// Used to determine and report recursive module inclusions.
    pub included_mod_stack: Lock<Vec<PathBuf>>,
    source_map: Lrc<SourceMap>,
    pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
    /// Contains the spans of block expressions that could have been incomplete based on the
    /// operation token that followed it, but that the parser cannot identify without further
    /// analysis.
    pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
    pub injected_crate_name: Once<Symbol>,
    pub gated_spans: GatedSpans,
    /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
    pub reached_eof: Lock<bool>,
}

impl ParseSess {
    pub fn new(file_path_mapping: FilePathMapping) -> Self {
        let cm = Lrc::new(SourceMap::new(file_path_mapping));
        let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, None, Some(cm.clone()));
        ParseSess::with_span_handler(handler, cm)
    }

    pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self {
        Self {
            span_diagnostic: handler,
            unstable_features: UnstableFeatures::from_environment(),
            config: FxHashSet::default(),
            edition: ExpnId::root().expn_data().edition,
            missing_fragment_specifiers: Lock::new(FxHashSet::default()),
            raw_identifier_spans: Lock::new(Vec::new()),
            included_mod_stack: Lock::new(vec![]),
            source_map,
            buffered_lints: Lock::new(vec![]),
            ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
            injected_crate_name: Once::new(),
            gated_spans: GatedSpans::default(),
            reached_eof: Lock::new(false),
        }
    }

    pub fn with_silent_emitter() -> Self {
        let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
        let handler = Handler::with_emitter(false, None, Box::new(SilentEmitter));
        ParseSess::with_span_handler(handler, cm)
    }

    #[inline]
    pub fn source_map(&self) -> &SourceMap {
        &self.source_map
    }

    pub fn buffer_lint(
        &self,
        lint: &'static Lint,
        span: impl Into<MultiSpan>,
        node_id: NodeId,
        msg: &str,
    ) {
        self.buffered_lints.with_lock(|buffered_lints| {
            buffered_lints.push(BufferedEarlyLint {
                span: span.into(),
                node_id,
                msg: msg.into(),
                lint_id: LintId::of(lint),
                diagnostic: BuiltinLintDiagnostics::Normal,
            });
        });
    }

    /// Extend an error with a suggestion to wrap an expression with parentheses to allow the
    /// parser to continue parsing the following operation as part of the same expression.
    pub fn expr_parentheses_needed(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        span: Span,
        alt_snippet: Option<String>,
    ) {
        if let Some(snippet) = self.source_map().span_to_snippet(span).ok().or(alt_snippet) {
            err.span_suggestion(
                span,
                "parentheses are required to parse this as an expression",
                format!("({})", snippet),
                Applicability::MachineApplicable,
            );
        }
    }
}
<|endoftext|>