<commit_before>//! Producer implementations.
extern crate rdkafka_sys as rdkafka;
extern crate errno;
extern crate futures;

use self::rdkafka::types::*;

use std::os::raw::c_void;
use std::ptr;
use std::sync::{Arc, RwLock};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::JoinHandle;
use std::thread;
use std::ffi::CString;

use self::futures::{Canceled, Complete, Future, Poll, Oneshot};

use client::{Client, Context};
use config::{ClientConfig, FromClientConfig, FromClientConfigAndContext, TopicConfig};
use error::{KafkaError, KafkaResult};
use message::ToBytes;
use util::cstr_to_owned;

/// A ProducerContext is a Context specific for producers. It can be used to store user-specified
/// callbacks, such as `delivery`.
pub trait ProducerContext: Context {
    /// A DeliveryContext is a user-defined structure that will be passed to the base producer when
    /// producing a message. The base producer will call the `received` method on this data once the
    /// associated message has been processed correctly.
    type DeliveryContext: Send + Sync;

    /// This method will be called once the message has beed delivered (or failed to). The
    /// DeliveryContext will be the one provided by the user when calling send.
    fn delivery(&self, DeliveryStatus, Self::DeliveryContext);
}

pub struct EmptyProducerContext;

impl Context for EmptyProducerContext { }
impl ProducerContext for EmptyProducerContext {
    type DeliveryContext = ();

    fn delivery(&self, _: DeliveryStatus, _: Self::DeliveryContext) { }
}

/// Contains a reference counted producer client. It can be safely cloned to
/// create another reference to the same producer.
pub struct BaseProducer<C: ProducerContext> {
    client: Arc<Client<C>>,
}

impl<C: ProducerContext> Clone for BaseProducer<C> {
    fn clone(&self) -> BaseProducer<C> {
        BaseProducer { client: self.client.clone() }
    }
}

#[derive(Debug)]
/// Information returned by the producer after a message has been delivered
/// or failed to be delivered.
pub struct DeliveryStatus {
    error: RDKafkaRespErr,
    partition: i32,
    offset: i64,
}

impl DeliveryStatus {
    /// Creates a new DeliveryStatus. This should only be used in the delivery_cb.
    fn new(err: RDKafkaRespErr, partition: i32, offset: i64) -> DeliveryStatus {
        DeliveryStatus {
            error: err,
            partition: partition,
            offset: offset,
        }
    }

    /// Returns the error associated with the production of the message.
    pub fn error(&self) -> RDKafkaRespErr {
        self.error
    }

    /// Returns the partition of the message.
    pub fn partition(&self) -> i32 {
        self.partition
    }

    /// Returns the offset of the message.
    pub fn offset(&self) -> i64 {
        self.offset
    }
}

/// Callback that gets called from librdkafka every time a message succeeds
/// or fails to be delivered.
unsafe extern "C" fn delivery_cb<C: ProducerContext>(_client: *mut RDKafka, msg: *const RDKafkaMessage, _opaque: *mut c_void) {
    let context = Box::from_raw(_opaque as *mut C);
    let delivery_context = Box::from_raw((*msg)._private as *mut C::DeliveryContext);
    let delivery_status = DeliveryStatus::new((*msg).err, (*msg).partition, (*msg).offset);
    trace!("Delivery event received: {:?}", delivery_status);
    (*context).delivery(delivery_status, (*delivery_context))
}

impl FromClientConfig for BaseProducer<EmptyProducerContext> {
    fn from_config(config: &ClientConfig) -> KafkaResult<BaseProducer<EmptyProducerContext>> {
        BaseProducer::from_config_and_context(config, EmptyProducerContext)
    }
}

/// Creates a new `BaseProducer` starting from a ClientConfig.
impl<C: ProducerContext> FromClientConfigAndContext<C> for BaseProducer<C> {
    fn from_config_and_context(config: &ClientConfig, context: C) -> KafkaResult<BaseProducer<C>> {
        let config_ptr = try!(config.create_native_config());
        unsafe { rdkafka::rd_kafka_conf_set_dr_msg_cb(config_ptr, Some(delivery_cb::<C>)) };
        let client = try!(Client::new(config_ptr, RDKafkaType::RD_KAFKA_PRODUCER, context));
        let producer = BaseProducer { client: Arc::new(client) };
        Ok(producer)
    }
}

impl<C: ProducerContext> BaseProducer<C> {
    /// Returns a topic associated to the producer
    pub fn get_topic(&self, name: &str, config: &TopicConfig) -> KafkaResult<ProducerTopic<C>> {
        ProducerTopic::new(&self, name, config)
    }

    /// Polls the producer. Regular calls to `poll` are required to process the evens
    /// and execute the message delivery callbacks.
    pub fn poll(&self, timeout_ms: i32) -> i32 {
        unsafe { rdkafka::rd_kafka_poll(self.client.native_ptr(), timeout_ms) }
    }

    pub fn client(&self) -> &Client<C> {
        self.client.as_ref()
    }
}

/// Represents a Kafka topic with an associated producer.
pub struct ProducerTopic<C: ProducerContext> {
    ptr: *mut RDKafkaTopic,
    producer: BaseProducer<C>,
}

impl<C: ProducerContext> ProducerTopic<C> {
    /// Creates the ProducerTopic.
    pub fn new(producer: &BaseProducer<C>, name: &str, topic_config: &TopicConfig) -> KafkaResult<ProducerTopic<C>> {
        let name_ptr = CString::new(name.to_string()).unwrap();
        let config_ptr = try!(topic_config.create_native_config());
        let topic_ptr = unsafe { rdkafka::rd_kafka_topic_new(producer.client().native_ptr(), name_ptr.as_ptr(), config_ptr) };
        if topic_ptr.is_null() {
            Err(KafkaError::TopicCreation(name.to_string()))
        } else {
            let topic = ProducerTopic {
                ptr: topic_ptr,
                producer: producer.clone(),
            };
            Ok(topic)
        }
    }

    /// Get topic's name
    pub fn get_name(&self) -> String {
        unsafe {
            cstr_to_owned(rdkafka::rd_kafka_topic_name(self.ptr))
        }
    }

    /// Returns a pointer to the correspondent rdkafka `RDKafkaTopic` struct.
    pub fn ptr(&self) -> *mut RDKafkaTopic {
        self.ptr
    }

    fn _send_copy(&self, partition: Option<i32>, payload: Option<&[u8]>, key: Option<&[u8]>,   delivery_context: Option<Box<C::DeliveryContext>>) -> KafkaResult<()> {
        let (payload_ptr, payload_len) = match payload {
            None => (ptr::null_mut(), 0),
            Some(p) => (p.as_ptr() as *mut c_void, p.len()),
        };
        let (key_ptr, key_len) = match key {
            None => (ptr::null_mut(), 0),
            Some(k) => (k.as_ptr() as *mut c_void, k.len()),
        };
        let delivery_context_ptr = match delivery_context {
            Some(context) => Box::into_raw(context) as *mut c_void,
            None => ptr::null_mut(),
        };
        let produce_response = unsafe {
            rdkafka::rd_kafka_produce(
                self.ptr(),
                partition.unwrap_or(-1),
                rdkafka::RD_KAFKA_MSG_F_COPY as i32,
                payload_ptr,
                payload_len,
                key_ptr,
                key_len,
                delivery_context_ptr,
            )
        };
        if produce_response != 0 {
            let errno = errno::errno().0 as i32;
            let kafka_error = unsafe { rdkafka::rd_kafka_errno2err(errno) };
            Err(KafkaError::MessageProduction(kafka_error))
        } else {
            Ok(())
        }
    }

    pub fn send_copy<P, K>(&self, partition: Option<i32>, payload: Option<&P>, key: Option<&K>, delivery_context: Option<Box<C::DeliveryContext>>) -> KafkaResult<()>
        where K: ToBytes,
              P: ToBytes {
        self._send_copy(partition, payload.map(P::to_bytes), key.map(K::to_bytes), delivery_context)
    }
}

impl<C: ProducerContext> Drop for ProducerTopic<C> {
    fn drop(&mut self) {
        trace!("Destroy rd_kafka_topic");
        unsafe {
            rdkafka::rd_kafka_topic_destroy(self.ptr);
        }
    }
}

/// The ProducerContext used by the FutureProducer. This context will use a Future as its
/// DeliveryContext and will complete the future when the message is delivered (or failed to). All
/// other callbacks will be delegated to the wrapped ProducerContext.
pub struct FutureProducerContext<C: ProducerContext> {
    _inner_context: C
}

impl<C: ProducerContext> Context for FutureProducerContext<C> {}

impl<C: ProducerContext> ProducerContext for FutureProducerContext<C> {
    type DeliveryContext = Complete<DeliveryStatus>;

    fn delivery(&self, status: DeliveryStatus, tx: Complete<DeliveryStatus>) {
        tx.complete(status);
    }
}

/// A producer with an internal running thread. This producer doesn't neeed to be polled.
/// The internal thread can be terminated with the `stop` method or moving the
/// `ProducerPollingThread` out of scope. The FutureProducer can be cheaply cloned
/// to create a reference to the same producer.
#[must_use = "Producer polling thread will stop immediately if unused"]
#[derive(Clone)]
pub struct FutureProducer<C: ProducerContext + 'static> {
    producer: BaseProducer<FutureProducerContext<C>>,
    should_stop: Arc<AtomicBool>,
    handle: Arc<RwLock<Option<JoinHandle<()>>>>,
}

impl FromClientConfig for FutureProducer<EmptyProducerContext> {
    fn from_config(config: &ClientConfig) -> KafkaResult<FutureProducer<EmptyProducerContext>> {
        FutureProducer::from_config_and_context(config, EmptyProducerContext)
    }
}

impl<C: ProducerContext> FromClientConfigAndContext<C> for FutureProducer<C> {
    fn from_config_and_context(config: &ClientConfig, context: C) -> KafkaResult<FutureProducer<C>> {
        let future_producer_context = FutureProducerContext{_inner_context: context} ;
        let future_producer = FutureProducer {
            producer: try!(BaseProducer::from_config_and_context(config, future_producer_context)),
            should_stop: Arc::new(AtomicBool::new(false)),
            handle: Arc::new(RwLock::new(None)),
        };
        Ok(future_producer)
    }
}

/// A future that will receive a `DeliveryStatus` containing information on the
/// delivery status of the message.
pub struct DeliveryFuture {
    rx: Oneshot<DeliveryStatus>,
}

impl Future for DeliveryFuture {
    type Item = DeliveryStatus;
    type Error = Canceled;

    fn poll(&mut self) -> Poll<DeliveryStatus, Canceled> {
        self.rx.poll()
    }
}

impl<C: ProducerContext> FutureProducer<C> {
    /// Returns a topic associated to the producer
    pub fn get_topic(&self, name: &str, config: &TopicConfig)
          -> KafkaResult<FutureProducerTopic<C>> {
        FutureProducerTopic::new(self, name, config)
    }

    pub fn base_producer(&self) -> &BaseProducer<FutureProducerContext<C>> {
        &self.producer
    }

    /// Starts the internal polling thread.
    pub fn start(&mut self) {
        let producer_clone = self.producer.clone();
        let should_stop = self.should_stop.clone();
        let handle = thread::Builder::new()
            .name("polling thread".to_string())
            .spawn(move || {
                 trace!("Polling thread loop started");
                 while !should_stop.load(Ordering::Relaxed) {
                     let n = producer_clone.poll(100);
                     if n != 0 {
                         trace!("Receved {} events", n);
                     }
                 }
                 trace!("Polling thread loop terminated");
            })
            .expect("Failed to start polling thread");
        match self.handle.write() {
            Ok(mut handle_ref) => *handle_ref = Some(handle),
            Err(_) => panic!("Poison error"),
        };
    }

    /// Stops the internal polling thread. The thread can also be stopped by moving
    /// the ProducerPollingThread out of scope.
    pub fn stop(&mut self) {
        match self.handle.write() {
            Ok(mut handle) => {
                if handle.is_some() {
                    trace!("Stopping polling");
                    self.should_stop.store(true, Ordering::Relaxed);
                    trace!("Waiting for polling thread termination");
                    match handle.take().unwrap().join() {
                        Ok(()) => trace!("Polling stopped"),
                        Err(e) => warn!("Failure while terminating thread: {:?}", e),
                    };
                }
            },
            Err(_) => {},
        };
    }
}

pub struct FutureProducerTopic<C: ProducerContext> {
    inner: ProducerTopic<FutureProducerContext<C>>
}

impl<C: ProducerContext> FutureProducerTopic<C> {
    /// Creates the ProducerTopic.
    pub fn new(producer: &FutureProducer<C>, name: &str, topic_config: &TopicConfig) -> KafkaResult<FutureProducerTopic<C>> {
        let future_producer_topic = FutureProducerTopic {
            inner: try!(ProducerTopic::new(producer.base_producer(), name, topic_config))
        };
        Ok(future_producer_topic)
    }

    /// Sends a copy of the payload and key provided to the specified topic. When no partition is
    /// specified the underlying Kafka library picks a partition based on the key.
    /// Returns a `DeliveryFuture` or an error.
    pub fn send_copy<P, K>(&self, partition: Option<i32>, payload: Option<&P>, key: Option<&K>) -> KafkaResult<DeliveryFuture>
        where K: ToBytes,
              P: ToBytes {
        let (tx, rx) = futures::oneshot();
        try!(self.inner.send_copy(partition, payload, key, Some(Box::new(tx))));
        Ok(DeliveryFuture{rx: rx})
    }
}

impl<C: ProducerContext> Drop for FutureProducer<C> {
    fn drop(&mut self) {
        trace!("Destroy ProducerPollingThread");
        self.stop();
    }
}
<commit_msg>Add docs<commit_after>//! Producer implementations.
extern crate rdkafka_sys as rdkafka;
extern crate errno;
extern crate futures;

use self::rdkafka::types::*;

use std::os::raw::c_void;
use std::ptr;
use std::sync::{Arc, RwLock};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::JoinHandle;
use std::thread;
use std::ffi::CString;

use self::futures::{Canceled, Complete, Future, Poll, Oneshot};

use client::{Client, Context};
use config::{ClientConfig, FromClientConfig, FromClientConfigAndContext, TopicConfig};
use error::{KafkaError, KafkaResult};
use message::ToBytes;
use util::cstr_to_owned;

/// A ProducerContext is a Context specific for producers. It can be used to store user-specified
/// callbacks, such as `delivery`.
pub trait ProducerContext: Context {
    /// A DeliveryContext is a user-defined structure that will be passed to the base producer when
    /// producing a message. The base producer will call the `received` method on this data once the
    /// associated message has been processed correctly.
    type DeliveryContext: Send + Sync;

    /// This method will be called once the message has beed delivered (or failed to). The
    /// DeliveryContext will be the one provided by the user when calling send.
    fn delivery(&self, DeliveryStatus, Self::DeliveryContext);
}

pub struct EmptyProducerContext;

impl Context for EmptyProducerContext { }
impl ProducerContext for EmptyProducerContext {
    type DeliveryContext = ();

    fn delivery(&self, _: DeliveryStatus, _: Self::DeliveryContext) { }
}

/// Contains a reference counted producer client. It can be safely cloned to
/// create another reference to the same producer.
pub struct BaseProducer<C: ProducerContext> {
    client: Arc<Client<C>>,
}

impl<C: ProducerContext> Clone for BaseProducer<C> {
    fn clone(&self) -> BaseProducer<C> {
        BaseProducer { client: self.client.clone() }
    }
}

#[derive(Debug)]
/// Information returned by the producer after a message has been delivered
/// or failed to be delivered.
pub struct DeliveryStatus {
    error: RDKafkaRespErr,
    partition: i32,
    offset: i64,
}

impl DeliveryStatus {
    /// Creates a new DeliveryStatus. This should only be used in the delivery_cb.
    fn new(err: RDKafkaRespErr, partition: i32, offset: i64) -> DeliveryStatus {
        DeliveryStatus {
            error: err,
            partition: partition,
            offset: offset,
        }
    }

    /// Returns the error associated with the production of the message.
    pub fn error(&self) -> RDKafkaRespErr {
        self.error
    }

    /// Returns the partition of the message.
    pub fn partition(&self) -> i32 {
        self.partition
    }

    /// Returns the offset of the message.
    pub fn offset(&self) -> i64 {
        self.offset
    }
}

/// Callback that gets called from librdkafka every time a message succeeds
/// or fails to be delivered.
unsafe extern "C" fn delivery_cb<C: ProducerContext>(_client: *mut RDKafka, msg: *const RDKafkaMessage, _opaque: *mut c_void) {
    let context = Box::from_raw(_opaque as *mut C);
    let delivery_context = Box::from_raw((*msg)._private as *mut C::DeliveryContext);
    let delivery_status = DeliveryStatus::new((*msg).err, (*msg).partition, (*msg).offset);
    trace!("Delivery event received: {:?}", delivery_status);
    (*context).delivery(delivery_status, (*delivery_context))
}

impl FromClientConfig for BaseProducer<EmptyProducerContext> {
    fn from_config(config: &ClientConfig) -> KafkaResult<BaseProducer<EmptyProducerContext>> {
        BaseProducer::from_config_and_context(config, EmptyProducerContext)
    }
}

/// Creates a new `BaseProducer` starting from a ClientConfig.
impl<C: ProducerContext> FromClientConfigAndContext<C> for BaseProducer<C> {
    fn from_config_and_context(config: &ClientConfig, context: C) -> KafkaResult<BaseProducer<C>> {
        let config_ptr = try!(config.create_native_config());
        unsafe { rdkafka::rd_kafka_conf_set_dr_msg_cb(config_ptr, Some(delivery_cb::<C>)) };
        let client = try!(Client::new(config_ptr, RDKafkaType::RD_KAFKA_PRODUCER, context));
        let producer = BaseProducer { client: Arc::new(client) };
        Ok(producer)
    }
}

impl<C: ProducerContext> BaseProducer<C> {
    /// Returns a topic associated to the producer
    pub fn get_topic(&self, name: &str, config: &TopicConfig) -> KafkaResult<ProducerTopic<C>> {
        ProducerTopic::new(&self, name, config)
    }

    /// Polls the producer. Regular calls to `poll` are required to process the evens
    /// and execute the message delivery callbacks.
    pub fn poll(&self, timeout_ms: i32) -> i32 {
        unsafe { rdkafka::rd_kafka_poll(self.client.native_ptr(), timeout_ms) }
    }

    pub fn client(&self) -> &Client<C> {
        self.client.as_ref()
    }
}

/// Represents a Kafka topic with an associated BaseProducer.
pub struct ProducerTopic<C: ProducerContext> {
    ptr: *mut RDKafkaTopic,
    producer: BaseProducer<C>,
}

impl<C: ProducerContext> ProducerTopic<C> {
    /// Creates the ProducerTopic.
    pub fn new(producer: &BaseProducer<C>, name: &str, topic_config: &TopicConfig) -> KafkaResult<ProducerTopic<C>> {
        let name_ptr = CString::new(name.to_string()).unwrap();
        let config_ptr = try!(topic_config.create_native_config());
        let topic_ptr = unsafe { rdkafka::rd_kafka_topic_new(producer.client().native_ptr(), name_ptr.as_ptr(), config_ptr) };
        if topic_ptr.is_null() {
            Err(KafkaError::TopicCreation(name.to_string()))
        } else {
            let topic = ProducerTopic {
                ptr: topic_ptr,
                producer: producer.clone(),
            };
            Ok(topic)
        }
    }

    /// Get topic's name
    pub fn get_name(&self) -> String {
        unsafe {
            cstr_to_owned(rdkafka::rd_kafka_topic_name(self.ptr))
        }
    }

    /// Returns a pointer to the correspondent rdkafka `RDKafkaTopic` struct.
    pub fn ptr(&self) -> *mut RDKafkaTopic {
        self.ptr
    }

    fn _send_copy(&self, partition: Option<i32>, payload: Option<&[u8]>, key: Option<&[u8]>,   delivery_context: Option<Box<C::DeliveryContext>>) -> KafkaResult<()> {
        let (payload_ptr, payload_len) = match payload {
            None => (ptr::null_mut(), 0),
            Some(p) => (p.as_ptr() as *mut c_void, p.len()),
        };
        let (key_ptr, key_len) = match key {
            None => (ptr::null_mut(), 0),
            Some(k) => (k.as_ptr() as *mut c_void, k.len()),
        };
        let delivery_context_ptr = match delivery_context {
            Some(context) => Box::into_raw(context) as *mut c_void,
            None => ptr::null_mut(),
        };
        let produce_response = unsafe {
            rdkafka::rd_kafka_produce(
                self.ptr(),
                partition.unwrap_or(-1),
                rdkafka::RD_KAFKA_MSG_F_COPY as i32,
                payload_ptr,
                payload_len,
                key_ptr,
                key_len,
                delivery_context_ptr,
            )
        };
        if produce_response != 0 {
            let errno = errno::errno().0 as i32;
            let kafka_error = unsafe { rdkafka::rd_kafka_errno2err(errno) };
            Err(KafkaError::MessageProduction(kafka_error))
        } else {
            Ok(())
        }
    }

    /// Sends a copy of the payload and key provided to the specified topic. When no partition is
    /// specified the underlying Kafka library picks a partition based on the key. If no key is
    /// specified, a random partition will be used.
    pub fn send_copy<P, K>(&self, partition: Option<i32>, payload: Option<&P>, key: Option<&K>, delivery_context: Option<Box<C::DeliveryContext>>) -> KafkaResult<()>
        where K: ToBytes,
              P: ToBytes {
        self._send_copy(partition, payload.map(P::to_bytes), key.map(K::to_bytes), delivery_context)
    }
}

impl<C: ProducerContext> Drop for ProducerTopic<C> {
    fn drop(&mut self) {
        trace!("Destroy rd_kafka_topic");
        unsafe {
            rdkafka::rd_kafka_topic_destroy(self.ptr);
        }
    }
}

/// The ProducerContext used by the FutureProducer. This context will use a Future as its
/// DeliveryContext and will complete the future when the message is delivered (or failed to). All
/// other callbacks will be delegated to the wrapped ProducerContext.
pub struct FutureProducerContext<C: ProducerContext> {
    _inner_context: C
}

impl<C: ProducerContext> Context for FutureProducerContext<C> {}

impl<C: ProducerContext> ProducerContext for FutureProducerContext<C> {
    type DeliveryContext = Complete<DeliveryStatus>;

    fn delivery(&self, status: DeliveryStatus, tx: Complete<DeliveryStatus>) {
        tx.complete(status);
    }
}

/// A producer with an internal running thread. This producer doesn't neeed to be polled.
/// The internal thread can be terminated with the `stop` method or moving the
/// `ProducerPollingThread` out of scope. The FutureProducer can be cheaply cloned
/// to create a new reference to the same producer.
#[must_use = "Producer polling thread will stop immediately if unused"]
#[derive(Clone)]
pub struct FutureProducer<C: ProducerContext + 'static> {
    producer: BaseProducer<FutureProducerContext<C>>,
    should_stop: Arc<AtomicBool>,
    handle: Arc<RwLock<Option<JoinHandle<()>>>>,
}

impl FromClientConfig for FutureProducer<EmptyProducerContext> {
    fn from_config(config: &ClientConfig) -> KafkaResult<FutureProducer<EmptyProducerContext>> {
        FutureProducer::from_config_and_context(config, EmptyProducerContext)
    }
}

impl<C: ProducerContext> FromClientConfigAndContext<C> for FutureProducer<C> {
    fn from_config_and_context(config: &ClientConfig, context: C) -> KafkaResult<FutureProducer<C>> {
        let future_producer_context = FutureProducerContext{_inner_context: context} ;
        let future_producer = FutureProducer {
            producer: try!(BaseProducer::from_config_and_context(config, future_producer_context)),
            should_stop: Arc::new(AtomicBool::new(false)),
            handle: Arc::new(RwLock::new(None)),
        };
        Ok(future_producer)
    }
}

/// A future that will receive a `DeliveryStatus` containing information on the
/// delivery status of the message.
pub struct DeliveryFuture {
    rx: Oneshot<DeliveryStatus>,
}

impl Future for DeliveryFuture {
    type Item = DeliveryStatus;
    type Error = Canceled;

    fn poll(&mut self) -> Poll<DeliveryStatus, Canceled> {
        self.rx.poll()
    }
}

impl<C: ProducerContext> FutureProducer<C> {
    /// Returns a topic associated to the producer
    pub fn get_topic(&self, name: &str, config: &TopicConfig)
          -> KafkaResult<FutureProducerTopic<C>> {
        FutureProducerTopic::new(self, name, config)
    }

    pub fn base_producer(&self) -> &BaseProducer<FutureProducerContext<C>> {
        &self.producer
    }

    /// Starts the internal polling thread.
    pub fn start(&mut self) {
        let producer_clone = self.producer.clone();
        let should_stop = self.should_stop.clone();
        let handle = thread::Builder::new()
            .name("polling thread".to_string())
            .spawn(move || {
                 trace!("Polling thread loop started");
                 while !should_stop.load(Ordering::Relaxed) {
                     let n = producer_clone.poll(100);
                     if n != 0 {
                         trace!("Receved {} events", n);
                     }
                 }
                 trace!("Polling thread loop terminated");
            })
            .expect("Failed to start polling thread");
        match self.handle.write() {
            Ok(mut handle_ref) => *handle_ref = Some(handle),
            Err(_) => panic!("Poison error"),
        };
    }

    /// Stops the internal polling thread. The thread can also be stopped by moving
    /// the ProducerPollingThread out of scope.
    pub fn stop(&mut self) {
        match self.handle.write() {
            Ok(mut handle) => {
                if handle.is_some() {
                    trace!("Stopping polling");
                    self.should_stop.store(true, Ordering::Relaxed);
                    trace!("Waiting for polling thread termination");
                    match handle.take().unwrap().join() {
                        Ok(()) => trace!("Polling stopped"),
                        Err(e) => warn!("Failure while terminating thread: {:?}", e),
                    };
                }
            },
            Err(_) => {},
        };
    }
}

/// A topic with associated FutureProducer.
pub struct FutureProducerTopic<C: ProducerContext> {
    inner: ProducerTopic<FutureProducerContext<C>>
}

impl<C: ProducerContext> FutureProducerTopic<C> {
    /// Creates the ProducerTopic.
    pub fn new(producer: &FutureProducer<C>, name: &str, topic_config: &TopicConfig) -> KafkaResult<FutureProducerTopic<C>> {
        let future_producer_topic = FutureProducerTopic {
            inner: try!(ProducerTopic::new(producer.base_producer(), name, topic_config))
        };
        Ok(future_producer_topic)
    }

    /// Sends a copy of the payload and key provided to the specified topic. When no partition is
    /// specified the underlying Kafka library picks a partition based on the key.
    /// Returns a `DeliveryFuture` or an error.
    pub fn send_copy<P, K>(&self, partition: Option<i32>, payload: Option<&P>, key: Option<&K>) -> KafkaResult<DeliveryFuture>
        where K: ToBytes,
              P: ToBytes {
        let (tx, rx) = futures::oneshot();
        try!(self.inner.send_copy(partition, payload, key, Some(Box::new(tx))));
        Ok(DeliveryFuture{rx: rx})
    }
}

impl<C: ProducerContext> Drop for FutureProducer<C> {
    fn drop(&mut self) {
        trace!("Destroy ProducerPollingThread");
        self.stop();
    }
}
<|endoftext|>


<commit_before>/*!
 * Entity component system
 */

extern crate rustc_serialize;

use std::default::{Default};
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::collections::{HashMap, HashSet};
use std::collections::hash_set;

/// Entity unique identifier type.
type Uid = i32;

/// Handle for an entity in the entity component system.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, RustcDecodable, RustcEncodable)]
pub struct Entity {
    /// Unique identifier for the entity.
    ///
    /// No two entities should get the same UID during the lifetime of the ECS.
    /// UIDs for regular entities are increasing positive integers.
    uid: Uid,
}

pub trait AnyComponent {
    /// Remove an entity's component.
    fn remove(&mut self, e: Entity);
}

/// Storage for a single component type.
#[derive(RustcEncodable, RustcDecodable)]
pub struct ComponentData<C> {
    // TODO: Add reused index fields to entities and use VecMap with the
    // index field instead of HashMap with the UID here for more
    // efficient access.
    data: HashMap<Uid, C>,
}

impl<C> ComponentData<C> {
    pub fn new() -> ComponentData<C> {
        ComponentData {
            data: HashMap::new()
        }
    }

    /// Insert a component to an entity.
    pub fn insert(&mut self, e: Entity, comp: C) {
        self.data.insert(e.uid, comp);
    }

    /// Return whether an entity contains this component.
    pub fn contains(&self, e: Entity) -> bool {
        self.data.contains_key(&e.uid)
    }
}

impl<C> Index<Entity> for ComponentData<C> {
    type Output = C;

    fn index<'a>(&'a self, e: Entity) -> &'a C {
        self.data.get(&e.uid).unwrap()
    }
}

impl<C> IndexMut<Entity> for ComponentData<C> {
    fn index_mut<'a>(&'a mut self, e: Entity) -> &'a mut C {
        self.data.get_mut(&e.uid).unwrap()
    }
}

impl<C> AnyComponent for ComponentData<C> {
    fn remove(&mut self, e: Entity) {
        self.data.remove(&e.uid);
    }
}

pub trait Store {
    /// Perform an operation for each component container.
    fn for_each_component<F>(&mut self, f: F)
        where F: FnMut(&mut AnyComponent);
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct Ecs<S> {
    next_uid: Uid,
    active: HashSet<Entity>,
    store: S,
}

impl<S: Default+Store> Ecs<S> {
    pub fn new() -> Ecs<S> {
        Ecs {
            next_uid: 1,
            active: HashSet::new(),
            store: Default::default(),
        }
    }

    /// Create a new empty entity.
    pub fn make(&mut self) -> Entity {
        let next = self.next_uid;
        self.next_uid += 1;
        let ret = Entity { uid: next };
        self.active.insert(ret);
        ret
    }

    /// Remove an entity from the system and clear its components.
    pub fn remove(&mut self, e: Entity) {
        self.active.remove(&e);
        self.store.for_each_component(|c| c.remove(e));
    }

    /// Return whether the system contains an entity.
    pub fn contains(&self, e: Entity) -> bool {
        self.active.contains(&e)
    }

    pub fn iter(&self) -> hash_set::Iter<Entity> {
        self.active.iter()
    }
}

impl<S> Deref for Ecs<S> {
    type Target = S;

    fn deref(&self) -> &S { &self.store }
}

impl<S> DerefMut for Ecs<S> {
    fn deref_mut(&mut self) -> &mut S {&mut self.store}
}

/// Entity component system builder macro.
///
/// Defines a local `Ecs` type that's parametrized with a custom component
/// store type with the component types you specify. Will also define a trait
/// `Component` which will be implemented for the component types.
#[macro_export]
macro_rules! Ecs {
    {
        // Declare the type of the (plain old data) component and the
        // identifier to use for it in the ECS.
        $($compname:ident: $comptype:ty,)+
    } => {
        mod _ecs_inner {
            // Use the enum to convert components to numbers for component bit masks etc.
            #[allow(non_camel_case_types, dead_code)]
            pub enum ComponentNum {
                $($compname,)+
            }

        }

        pub use self::_ecs_inner::ComponentNum;

#[derive(RustcEncodable, RustcDecodable)]
        pub struct _ComponentStore {
            $(pub $compname: ::calx_ecs::ComponentData<$comptype>),+
        }

        impl ::std::default::Default for _ComponentStore {
            fn default() -> _ComponentStore {
                _ComponentStore {
                    $($compname: ::calx_ecs::ComponentData::new()),+
                }
            }
        }

        impl ::calx_ecs::Store for _ComponentStore {
            fn for_each_component<F>(&mut self, mut f: F)
                where F: FnMut(&mut ::calx_ecs::AnyComponent)
            {
                $(f(&mut self.$compname as &mut ::calx_ecs::AnyComponent);)+
            }
        }

#[allow(dead_code)]
        pub fn matches_mask(ecs: &::calx_ecs::Ecs<_ComponentStore>, e: ::calx_ecs::Entity, mask: u64) -> bool {
            $(if mask & (1 << ComponentNum::$compname as u8) != 0 && !ecs.$compname.contains(e) {
                return false;
            })+
            return true;
        }

        /// Common operations for ECS component value types.
        pub trait Component {
            /// Add a clone of the component value to an entity in an ECS.
            ///
            /// Can't move the component itself since we might be using this
            /// through a trait object.
            fn add_to(&self, ecs: &mut ::calx_ecs::Ecs<_ComponentStore>, e: ::calx_ecs::Entity);
        }

        $(impl Component for $comptype {
            fn add_to(&self, ecs: &mut ::calx_ecs::Ecs<_ComponentStore>, e: ::calx_ecs::Entity) {
                ecs.$compname.insert(e, self.clone());
            }
        })+

        pub type Ecs = ::calx_ecs::Ecs<_ComponentStore>;
    }
}

/// Build a vector of Component trait objects from component values.
///
/// Use to set up prototype templates for entities.
#[macro_export]
macro_rules! loadout {
    [ $($comp:expr),+ ] => {
        vec![
            $(Box::new($comp) as Box<Component>),+
        ]
    }
}

/// Build a component type mask to match component iteration with.
///
/// You must have ComponentNum enum from the Ecs! macro expansion in scope
/// when using this.
#[macro_export]
macro_rules! build_mask {
    ( $($compname:ident),+ ) => {
        0u64 $(| (1u64 << ComponentNum::$compname as u8))+
    }
}
<commit_msg>Public entity UID field<commit_after>/*!
 * Entity component system
 */

extern crate rustc_serialize;

use std::default::{Default};
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::collections::{HashMap, HashSet};
use std::collections::hash_set;

/// Handle for an entity in the entity component system.
///
/// The internal value is the unique identifier for the entity. No two
/// entities should get the same UID during the lifetime of the ECS.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, RustcDecodable, RustcEncodable)]
pub struct Entity(pub usize);

pub trait AnyComponent {
    /// Remove an entity's component.
    fn remove(&mut self, e: Entity);
}

/// Storage for a single component type.
#[derive(RustcEncodable, RustcDecodable)]
pub struct ComponentData<C> {
    // TODO: Add reused index fields to entities and use VecMap with the
    // index field instead of HashMap with the UID here for more
    // efficient access.
    data: HashMap<usize, C>,
}

impl<C> ComponentData<C> {
    pub fn new() -> ComponentData<C> {
        ComponentData {
            data: HashMap::new()
        }
    }

    /// Insert a component to an entity.
    pub fn insert(&mut self, Entity(uid): Entity, comp: C) {
        self.data.insert(uid, comp);
    }

    /// Return whether an entity contains this component.
    pub fn contains(&self, Entity(uid): Entity) -> bool {
        self.data.contains_key(&uid)
    }
}

impl<C> Index<Entity> for ComponentData<C> {
    type Output = C;

    fn index<'a>(&'a self, Entity(uid): Entity) -> &'a C {
        self.data.get(&uid).unwrap()
    }
}

impl<C> IndexMut<Entity> for ComponentData<C> {
    fn index_mut<'a>(&'a mut self, Entity(uid): Entity) -> &'a mut C {
        self.data.get_mut(&uid).unwrap()
    }
}

impl<C> AnyComponent for ComponentData<C> {
    fn remove(&mut self, Entity(uid): Entity) {
        self.data.remove(&uid);
    }
}

pub trait Store {
    /// Perform an operation for each component container.
    fn for_each_component<F>(&mut self, f: F)
        where F: FnMut(&mut AnyComponent);
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct Ecs<S> {
    next_uid: usize,
    active: HashSet<Entity>,
    store: S,
}

impl<S: Default+Store> Ecs<S> {
    pub fn new() -> Ecs<S> {
        Ecs {
            next_uid: 1,
            active: HashSet::new(),
            store: Default::default(),
        }
    }

    /// Create a new empty entity.
    pub fn make(&mut self) -> Entity {
        let next = self.next_uid;
        self.next_uid += 1;
        let ret = Entity(next);
        self.active.insert(ret);
        ret
    }

    /// Remove an entity from the system and clear its components.
    pub fn remove(&mut self, e: Entity) {
        self.active.remove(&e);
        self.store.for_each_component(|c| c.remove(e));
    }

    /// Return whether the system contains an entity.
    pub fn contains(&self, e: Entity) -> bool {
        self.active.contains(&e)
    }

    pub fn iter(&self) -> hash_set::Iter<Entity> {
        self.active.iter()
    }
}

impl<S> Deref for Ecs<S> {
    type Target = S;

    fn deref(&self) -> &S { &self.store }
}

impl<S> DerefMut for Ecs<S> {
    fn deref_mut(&mut self) -> &mut S {&mut self.store}
}

/// Entity component system builder macro.
///
/// Defines a local `Ecs` type that's parametrized with a custom component
/// store type with the component types you specify. Will also define a trait
/// `Component` which will be implemented for the component types.
#[macro_export]
macro_rules! Ecs {
    {
        // Declare the type of the (plain old data) component and the
        // identifier to use for it in the ECS.
        $($compname:ident: $comptype:ty,)+
    } => {
        mod _ecs_inner {
            // Use the enum to convert components to numbers for component bit masks etc.
            #[allow(non_camel_case_types, dead_code)]
            pub enum ComponentNum {
                $($compname,)+
            }

        }

        pub use self::_ecs_inner::ComponentNum;

#[derive(RustcEncodable, RustcDecodable)]
        pub struct _ComponentStore {
            $(pub $compname: ::calx_ecs::ComponentData<$comptype>),+
        }

        impl ::std::default::Default for _ComponentStore {
            fn default() -> _ComponentStore {
                _ComponentStore {
                    $($compname: ::calx_ecs::ComponentData::new()),+
                }
            }
        }

        impl ::calx_ecs::Store for _ComponentStore {
            fn for_each_component<F>(&mut self, mut f: F)
                where F: FnMut(&mut ::calx_ecs::AnyComponent)
            {
                $(f(&mut self.$compname as &mut ::calx_ecs::AnyComponent);)+
            }
        }

#[allow(dead_code)]
        pub fn matches_mask(ecs: &::calx_ecs::Ecs<_ComponentStore>, e: ::calx_ecs::Entity, mask: u64) -> bool {
            $(if mask & (1 << ComponentNum::$compname as u8) != 0 && !ecs.$compname.contains(e) {
                return false;
            })+
            return true;
        }

        /// Common operations for ECS component value types.
        pub trait Component {
            /// Add a clone of the component value to an entity in an ECS.
            ///
            /// Can't move the component itself since we might be using this
            /// through a trait object.
            fn add_to(&self, ecs: &mut ::calx_ecs::Ecs<_ComponentStore>, e: ::calx_ecs::Entity);
        }

        $(impl Component for $comptype {
            fn add_to(&self, ecs: &mut ::calx_ecs::Ecs<_ComponentStore>, e: ::calx_ecs::Entity) {
                ecs.$compname.insert(e, self.clone());
            }
        })+

        pub type Ecs = ::calx_ecs::Ecs<_ComponentStore>;
    }
}

/// Build a vector of Component trait objects from component values.
///
/// Use to set up prototype templates for entities.
#[macro_export]
macro_rules! loadout {
    [ $($comp:expr),+ ] => {
        vec![
            $(Box::new($comp) as Box<Component>),+
        ]
    }
}

/// Build a component type mask to match component iteration with.
///
/// You must have ComponentNum enum from the Ecs! macro expansion in scope
/// when using this.
#[macro_export]
macro_rules! build_mask {
    ( $($compname:ident),+ ) => {
        0u64 $(| (1u64 << ComponentNum::$compname as u8))+
    }
}
<|endoftext|>


<commit_before>use libc;
use ram::entry;
use ram::tombstone::{TOMBSTONE_SIZE_U32, Tombstone};
use ram::cell;
use ram::cell::Cell;
use ram::chunk::Chunk;
use ram::entry::EntryMeta;
use std::sync::atomic::{AtomicUsize, AtomicU32, AtomicI64, AtomicBool, Ordering};
use std::collections::BTreeSet;
use std::fs::{File, remove_file, copy};
use std::io::BufWriter;
use std::io::prelude::*;
use std::io;
use std::path::Path;
use crc32c::crc32c;
use bifrost::utils::async_locks::{RwLock, RwLockReadGuard};
use parking_lot;

use super::cell::CellHeader;

pub const MAX_SEGMENT_SIZE_U32: u32 = 8 * 1024 * 1024;
pub const MAX_SEGMENT_SIZE: usize = MAX_SEGMENT_SIZE_U32 as usize;

pub struct Segment {
    pub id: u64,
    pub addr: usize,
    pub bound: usize,
    pub append_header: AtomicUsize,
    pub dead_space: AtomicU32,
    pub tombstones: AtomicU32,
    pub dead_tombstones: AtomicU32,
    pub last_tombstones_scanned: AtomicI64,
    pub references: AtomicUsize,
    pub backup_file_name: Option<String>,
    pub wal_file: Option<parking_lot::Mutex<BufWriter<File>>>,
    pub wal_file_name: Option<String>,
    pub archived: AtomicBool,
    pub dropped: AtomicBool
}

impl Segment {
    pub fn new(id: u64, size: usize,
               backup_storage: &Option<String>,
               wal_storage: &Option<String>) -> Segment {
        let buffer_ptr = unsafe { libc::malloc(size) as usize };
        let mut wal_file_name = None;
        let mut wal_file = None;
        if let Some(wal_storage) = wal_storage {
            let file_name = format!("{}/{}.log", wal_storage, id);
            let file = BufWriter::with_capacity(
                4096, // most common disk block size
                File::open(&file_name).unwrap()); // fast fail
            wal_file_name = Some(file_name);
            wal_file = Some(parking_lot::Mutex::new(file));
        }
        debug!("Creating new segment with id {}, size {}, address {}", id, size, buffer_ptr);
        Segment {
            addr: buffer_ptr,
            id,
            bound: buffer_ptr + size,
            append_header: AtomicUsize::new(buffer_ptr),
            dead_space: AtomicU32::new(0),
            tombstones: AtomicU32::new(0),
            dead_tombstones: AtomicU32::new(0),
            last_tombstones_scanned: AtomicI64::new(0),
            references: AtomicUsize::new(0),
            backup_file_name: backup_storage.clone().map(|path| format!("{}/{}.backup", path, id)),
            archived: AtomicBool::new(false),
            dropped: AtomicBool::new(false),
            wal_file,
            wal_file_name
        }
    }

    pub fn try_acquire(&self, size: u32) -> Option<usize> {
        let size = size as usize;
        loop {
            let curr_last = self.append_header.load(Ordering::SeqCst);
            let exp_last = curr_last + size;
            if exp_last > self.bound {
                return None;
            } else {
                if self.append_header.compare_and_swap(curr_last, exp_last, Ordering::SeqCst) != curr_last {
                    continue;
                } else {
                    return Some(curr_last);
                }
            }
        }
    }

    fn append_header(&self) -> usize {
        self.append_header.load(Ordering::Relaxed)
    }

    pub fn entry_iter(&self) -> SegmentEntryIter {
        SegmentEntryIter {
            bound: self.append_header(),
            cursor: self.addr
        }
    }

    pub fn dead_space(&self) -> u32 {
        self.dead_space.load(Ordering::Relaxed)
    }

    // dead space plus tombstone spaces
    pub fn total_dead_space(&self) -> u32 {
        let dead_tombstones_space = self.dead_tombstones.load(Ordering::Relaxed) * TOMBSTONE_SIZE_U32;
        let dead_cells_space = self.dead_space();
        return dead_tombstones_space + dead_cells_space;
    }

    pub fn used_spaces(&self) -> u32 {
        return (self.append_header.load(Ordering::Relaxed) as usize - self.addr) as u32
    }

    pub fn living_space(&self) -> u32 {
        let total_dead_space = self.total_dead_space();
        let used_space = self.used_spaces();
        debug_assert!(total_dead_space <= used_space);
        used_space - total_dead_space
    }

    pub fn valid_space(&self) -> u32 {
        return self.used_spaces() - self.dead_space();
    }

    pub fn living_rate(&self) -> f32 {
        let used_space = self.used_spaces() as f32;
        if used_space == 0f32 {
            // empty segment
            return 1f32;
        }
        return self.living_space() as f32 / used_space;
    }

    // archive this segment and write the data to backup storage
    pub fn archive(&self) -> Result<bool, io::Error> {
        if let &Some(ref backup_file) = &self.backup_file_name {
            while !self.no_references() { /* wait until all references released */}
            let backup_file_path = Path::new(backup_file);
            if backup_file_path.exists() {
                warn!("Segment backup {} exists and can't archive twice", backup_file);
                return Ok(false);
            }
            if let Some(ref wal_file) = self.wal_file_name {
                // if there is a WAL file ready, copy this file to backup
                if let Some(ref file_mutex) = self.wal_file {
                    // this should be redundant but I don't want to take the chance
                    // obtain the writer lock before continue
                    let _ = file_mutex.lock();
                    copy(wal_file, backup_file);
                    remove_file(wal_file);
                } else { panic!() }

            } else {
                let backup_file = File::open(backup_file_path)?;
                let seg_size = self.append_header.load(Ordering::Relaxed) - self.addr;
                let mut buffer = BufWriter::with_capacity(seg_size, backup_file);
                unsafe {
                    for offset in 0..seg_size {
                        let ptr = (self.addr + offset) as *const u8;
                        let byte = *ptr;
                        buffer.write(&[byte])?;
                    }
                }
                buffer.flush()?;
                return Ok(true);
            }
        }
        return Ok(false);
    }

    pub fn write_wal(&self, addr: usize, size: u32) -> io::Result<()> {
        if let Some(ref wal_file) = self.wal_file {
            let mut file = wal_file.lock();
            unsafe {
                for offset in 0..size as usize {
                    let ptr = (addr + offset) as *const u8;
                    let byte = *ptr;
                    file.write(&[byte])?;
                }
            }
            file.flush()?;
        }
        return Ok(());
    }

    pub fn no_references(&self) -> bool { self.references.load(Ordering::Relaxed) == 0 }

    pub fn mem_drop(&self) {
        if !self.dropped.compare_and_swap(false, true, Ordering::Relaxed) {
            debug!("disposing segment at {}", self.addr);
            unsafe {
                libc::free(self.addr as *mut libc::c_void)
            }
        }
    }

    // remove the backup if it have one
    pub fn dispense(&self) {
        debug!("dispense segment {}", self.id);
        if let &Some(ref backup_storage) = &self.backup_file_name {
            let path = Path::new(backup_storage);
            if path.exists() {
                if let Err(e) = remove_file(path) {
                    error!("cannot reclaim segment file on dispense {}", backup_storage)
                }
            } else {
                error!("cannot find segment backup {}", backup_storage)
            }
        }
    }
}

impl Drop for Segment {
    fn drop(&mut self) {
        debug!("Memory dropping segment {}", self.id);
        assert_eq!(self.references.load(Ordering::Relaxed), 0);
        self.mem_drop()
    }
}

pub struct SegmentEntryIter {
    bound: usize,
    cursor: usize
}

impl Iterator for SegmentEntryIter {
    type Item = EntryMeta;

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        let cursor = self.cursor;
        if cursor >= self.bound {
            return None;
        }
        let (_, entry_meta) = entry::Entry::decode_from(
            cursor,
            |body_pos, header| {
                let entry_header_size = body_pos - cursor;
                let entry_size = entry_header_size + header.content_length as usize;
                debug!("Found body pos {}, entry header {:?}. Header size: {}, entry size: {}, entry pos: {}, content length {}, bound {}",
                       body_pos, header, entry_header_size, entry_size, cursor, header.content_length, self.bound);
                return EntryMeta {
                    body_pos, entry_header: header, entry_size, entry_pos: cursor
                };
            });
        self.cursor += entry_meta.entry_size;
        Some(entry_meta)
    }
}<commit_msg>still check and warn<commit_after>use libc;
use ram::entry;
use ram::tombstone::{TOMBSTONE_SIZE_U32, Tombstone};
use ram::cell;
use ram::cell::Cell;
use ram::chunk::Chunk;
use ram::entry::EntryMeta;
use std::sync::atomic::{AtomicUsize, AtomicU32, AtomicI64, AtomicBool, Ordering};
use std::collections::BTreeSet;
use std::fs::{File, remove_file, copy};
use std::io::BufWriter;
use std::io::prelude::*;
use std::io;
use std::path::Path;
use crc32c::crc32c;
use bifrost::utils::async_locks::{RwLock, RwLockReadGuard};
use parking_lot;

use super::cell::CellHeader;

pub const MAX_SEGMENT_SIZE_U32: u32 = 8 * 1024 * 1024;
pub const MAX_SEGMENT_SIZE: usize = MAX_SEGMENT_SIZE_U32 as usize;

pub struct Segment {
    pub id: u64,
    pub addr: usize,
    pub bound: usize,
    pub append_header: AtomicUsize,
    pub dead_space: AtomicU32,
    pub tombstones: AtomicU32,
    pub dead_tombstones: AtomicU32,
    pub last_tombstones_scanned: AtomicI64,
    pub references: AtomicUsize,
    pub backup_file_name: Option<String>,
    pub wal_file: Option<parking_lot::Mutex<BufWriter<File>>>,
    pub wal_file_name: Option<String>,
    pub archived: AtomicBool,
    pub dropped: AtomicBool
}

impl Segment {
    pub fn new(id: u64, size: usize,
               backup_storage: &Option<String>,
               wal_storage: &Option<String>) -> Segment {
        let buffer_ptr = unsafe { libc::malloc(size) as usize };
        let mut wal_file_name = None;
        let mut wal_file = None;
        if let Some(wal_storage) = wal_storage {
            let file_name = format!("{}/{}.log", wal_storage, id);
            let file = BufWriter::with_capacity(
                4096, // most common disk block size
                File::open(&file_name).unwrap()); // fast fail
            wal_file_name = Some(file_name);
            wal_file = Some(parking_lot::Mutex::new(file));
        }
        debug!("Creating new segment with id {}, size {}, address {}", id, size, buffer_ptr);
        Segment {
            addr: buffer_ptr,
            id,
            bound: buffer_ptr + size,
            append_header: AtomicUsize::new(buffer_ptr),
            dead_space: AtomicU32::new(0),
            tombstones: AtomicU32::new(0),
            dead_tombstones: AtomicU32::new(0),
            last_tombstones_scanned: AtomicI64::new(0),
            references: AtomicUsize::new(0),
            backup_file_name: backup_storage.clone().map(|path| format!("{}/{}.backup", path, id)),
            archived: AtomicBool::new(false),
            dropped: AtomicBool::new(false),
            wal_file,
            wal_file_name
        }
    }

    pub fn try_acquire(&self, size: u32) -> Option<usize> {
        let size = size as usize;
        loop {
            let curr_last = self.append_header.load(Ordering::SeqCst);
            let exp_last = curr_last + size;
            if exp_last > self.bound {
                return None;
            } else {
                if self.append_header.compare_and_swap(curr_last, exp_last, Ordering::SeqCst) != curr_last {
                    continue;
                } else {
                    return Some(curr_last);
                }
            }
        }
    }

    fn append_header(&self) -> usize {
        self.append_header.load(Ordering::Relaxed)
    }

    pub fn entry_iter(&self) -> SegmentEntryIter {
        SegmentEntryIter {
            bound: self.append_header(),
            cursor: self.addr
        }
    }

    pub fn dead_space(&self) -> u32 {
        self.dead_space.load(Ordering::Relaxed)
    }

    // dead space plus tombstone spaces
    pub fn total_dead_space(&self) -> u32 {
        let dead_tombstones_space = self.dead_tombstones.load(Ordering::Relaxed) * TOMBSTONE_SIZE_U32;
        let dead_cells_space = self.dead_space();
        return dead_tombstones_space + dead_cells_space;
    }

    pub fn used_spaces(&self) -> u32 {
        return (self.append_header.load(Ordering::Relaxed) as usize - self.addr) as u32
    }

    pub fn living_space(&self) -> u32 {
        let total_dead_space = self.total_dead_space();
        let used_space = self.used_spaces();
        if total_dead_space <= used_space {
            used_space - total_dead_space
        } else {
            warn!("living space check error for segment {}, used {}, dead {}",
                  self.id, used_space, total_dead_space);
            0
        }
    }

    pub fn valid_space(&self) -> u32 {
        return self.used_spaces() - self.dead_space();
    }

    pub fn living_rate(&self) -> f32 {
        let used_space = self.used_spaces() as f32;
        if used_space == 0f32 {
            // empty segment
            return 1f32;
        }
        return self.living_space() as f32 / used_space;
    }

    // archive this segment and write the data to backup storage
    pub fn archive(&self) -> Result<bool, io::Error> {
        if let &Some(ref backup_file) = &self.backup_file_name {
            while !self.no_references() { /* wait until all references released */}
            let backup_file_path = Path::new(backup_file);
            if backup_file_path.exists() {
                warn!("Segment backup {} exists and can't archive twice", backup_file);
                return Ok(false);
            }
            if let Some(ref wal_file) = self.wal_file_name {
                // if there is a WAL file ready, copy this file to backup
                if let Some(ref file_mutex) = self.wal_file {
                    // this should be redundant but I don't want to take the chance
                    // obtain the writer lock before continue
                    let _ = file_mutex.lock();
                    copy(wal_file, backup_file);
                    remove_file(wal_file);
                } else { panic!() }

            } else {
                let backup_file = File::open(backup_file_path)?;
                let seg_size = self.append_header.load(Ordering::Relaxed) - self.addr;
                let mut buffer = BufWriter::with_capacity(seg_size, backup_file);
                unsafe {
                    for offset in 0..seg_size {
                        let ptr = (self.addr + offset) as *const u8;
                        let byte = *ptr;
                        buffer.write(&[byte])?;
                    }
                }
                buffer.flush()?;
                return Ok(true);
            }
        }
        return Ok(false);
    }

    pub fn write_wal(&self, addr: usize, size: u32) -> io::Result<()> {
        if let Some(ref wal_file) = self.wal_file {
            let mut file = wal_file.lock();
            unsafe {
                for offset in 0..size as usize {
                    let ptr = (addr + offset) as *const u8;
                    let byte = *ptr;
                    file.write(&[byte])?;
                }
            }
            file.flush()?;
        }
        return Ok(());
    }

    pub fn no_references(&self) -> bool { self.references.load(Ordering::Relaxed) == 0 }

    pub fn mem_drop(&self) {
        if !self.dropped.compare_and_swap(false, true, Ordering::Relaxed) {
            debug!("disposing segment at {}", self.addr);
            unsafe {
                libc::free(self.addr as *mut libc::c_void)
            }
        }
    }

    // remove the backup if it have one
    pub fn dispense(&self) {
        debug!("dispense segment {}", self.id);
        if let &Some(ref backup_storage) = &self.backup_file_name {
            let path = Path::new(backup_storage);
            if path.exists() {
                if let Err(e) = remove_file(path) {
                    error!("cannot reclaim segment file on dispense {}", backup_storage)
                }
            } else {
                error!("cannot find segment backup {}", backup_storage)
            }
        }
    }
}

impl Drop for Segment {
    fn drop(&mut self) {
        debug!("Memory dropping segment {}", self.id);
        assert_eq!(self.references.load(Ordering::Relaxed), 0);
        self.mem_drop()
    }
}

pub struct SegmentEntryIter {
    bound: usize,
    cursor: usize
}

impl Iterator for SegmentEntryIter {
    type Item = EntryMeta;

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        let cursor = self.cursor;
        if cursor >= self.bound {
            return None;
        }
        let (_, entry_meta) = entry::Entry::decode_from(
            cursor,
            |body_pos, header| {
                let entry_header_size = body_pos - cursor;
                let entry_size = entry_header_size + header.content_length as usize;
                debug!("Found body pos {}, entry header {:?}. Header size: {}, entry size: {}, entry pos: {}, content length {}, bound {}",
                       body_pos, header, entry_header_size, entry_size, cursor, header.content_length, self.bound);
                return EntryMeta {
                    body_pos, entry_header: header, entry_size, entry_pos: cursor
                };
            });
        self.cursor += entry_meta.entry_size;
        Some(entry_meta)
    }
}<|endoftext|>


<commit_before>use std::fmt;
use std::collections::HashMap;
use fmt_code::{FormattedCode, Lang};
use string_gen::keywords::{NAME, TYPE, VALUE};

// (element name, attributes (Vec<name, value>), depth in API file structure)
pub type CodeData = (String, Vec<(String, String)>, u8);

#[derive(Clone)]
pub struct CodeItem {
    pub name: String,
    pub attributes: Vec<(String, String)>,
    pub children: Vec<CodeItem>
}

impl CodeItem {
    pub fn new(item_name: &str, item_attribs: Vec<(String, String)>) -> CodeItem {
        CodeItem {
            name: String::from(item_name),
            attributes: item_attribs,
            children: Vec::<CodeItem>::new()
        }
    }
}

pub struct CodeConfig {
    pub name: String,
    pub type_dict: HashMap<String, String>,
    pub name_dict: HashMap<String, String>,
    pub global_cfg: HashMap<String, String>
}

impl CodeConfig {
    pub fn new(cfg_name: &str) -> CodeConfig {
        CodeConfig {
            name: String::from(cfg_name),
            type_dict: HashMap::<String, String>::new(),
            name_dict: HashMap::<String, String>::new(),
            global_cfg: HashMap::<String, String>::new()
        }
    }
}

pub struct RawCode {
    pub configs: HashMap<String, CodeConfig>,
    pub elements: Vec<CodeItem>,
    supported_langs: HashMap<Lang, String>
}

impl RawCode {
    pub fn new() -> RawCode {
        let mut rc = RawCode {
            configs: HashMap::<String, CodeConfig>::new(),
            elements: Vec::<CodeItem>::new(),
            supported_langs: HashMap::<Lang, String>::new()
        };

        rc.supported_langs.insert(Lang::Cpp, String::from("cpp"));
        rc.supported_langs.insert(Lang::Rust, String::from("rust"));

        rc
    }

    // convert raw data to cpp code
    pub fn to_cpp(&self) -> FormattedCode {
        self.to_lang(Lang::Cpp)
    }
    // convert raw data to Rust code
    pub fn to_rust(&self) -> FormattedCode {
        self.to_lang(Lang::Rust)
    }

    fn to_lang(&self, lang: Lang) -> FormattedCode {
        let lang_idx = self.supported_langs.get(&lang).unwrap();
        FormattedCode::new(lang, &self.configs.get(lang_idx), &self.elements)
    }
}

impl fmt::Display for RawCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let _ = write!(f, "<raw data>\n");
        let _ = write!(f, "*\n");
        for e in self.elements.iter() {
            let mut empty_spaces = Vec::<u8>::new();
            print_code_item(e, f, 0, &mut empty_spaces);
        }
        write!(f, "*\n")
    }
}

impl fmt::Display for CodeConfig {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let _ = write!(f, "Config: {}\n", self.name);
        if self.global_cfg.len() > 0 {
            let _ = write!(f, "Settings:\n");
        }
        for (k, v) in &self.global_cfg {
            let _ = write!(f, " {} = {}\n", k, v);
        }
        if self.name_dict.len() > 0 {
            let _ = write!(f, "Names:\n");
        }
        for (k, v) in &self.name_dict {
            let _ = write!(f, "  {} = {}\n", k, v);
        }
        if self.type_dict.len() > 0 {
            let _ = write!(f, "Types:\n");
        }
        for (k, v) in &self.type_dict {
            let _ = write!(f, "  {} = {}\n", k, v);
        }
        write!(f, "")
    }
}

// used by Display trait to print the tree of elements
pub fn print_code_item(e: &CodeItem, f: &mut fmt::Formatter, depth: u8, empty_spaces: &mut Vec<u8>) {
    // indentation
    for i in 0..depth {
        let mut separator = "|";
        for j in empty_spaces.iter() {
            if i == *j {
                separator = " ";
                break;
            }
        }
        let _ = write!(f, "{}  ", separator);
    }

    let _ = write!(f, "|--{}", e.name);
    // print attributes
    if e.attributes.len() > 0 {
        let _ = write!(f, " [");
        for a in 0..e.attributes.len() {
            if a > 0 && a < e.attributes.len() {
                let _ = write!(f, ", ");
            }
            let _ = write!(f, "{}:\"{}\"", e.attributes[a].0, e.attributes[a].1);
        }
        let _ = write!(f, "]");
    }
    let _ = write!(f, "\n");

    // child processing
    if e.children.len() > 0 {
        for c in 0..e.children.len() {
            if (e.children.len() - c) == 1 {
                empty_spaces.push(depth+1);
            }
            else {
                empty_spaces.sort();
                let idx = empty_spaces.binary_search(&(depth+1));
                match idx { Ok(_) => { empty_spaces.remove(idx.unwrap()); }, _ => {} };
            }
            print_code_item(&e.children[c], f, depth+1, empty_spaces);
        }

        // reset space directory when topmost child is reached
        if depth == 1 {
            empty_spaces.clear();
        }
    }
}

// create RawCode element from pre-parsed data
pub fn generate_raw(data: &Vec<CodeData>, config_data: &Vec<CodeData>) -> RawCode {
    let mut raw_code = RawCode::new();

    for i in config_data.iter() {
        if !raw_code.configs.contains_key(&i.0) {
            raw_code.configs.insert(i.0.clone(), CodeConfig::new(&i.0));
        }

        let mut n = String::new();
        let mut t = String::new();
        let mut v = String::new();
        // process all config attributes
        for j in i.1.iter() {
            match j.0.as_str() {
                NAME  => n = j.1.clone(),
                TYPE  => t = j.1.clone(),
                VALUE => v = j.1.clone(),
                _ => { raw_code.configs.get_mut(&i.0).unwrap().global_cfg.insert(j.0.clone(), j.1.clone()); }
            }
        }

        if n.len() > 0 {
            assert!(raw_code.configs.get_mut(&i.0).unwrap().name_dict.insert(n.clone(), v.clone()) == None, "Name \"{}\" already defined in config! (duplicate: {}={})", n, n, v);
        }
        if t.len() > 0 {
            assert!(raw_code.configs.get_mut(&i.0).unwrap().type_dict.insert(t.clone(), v.clone()) == None, "Type \"{}\" already defined in config! (duplicate: {}={}", t, t, v);
        }
    }

    for i in data.iter() {
        // if at depth 0, it's a root element, so add it to the main list
        if i.2 == 0 {
            raw_code.elements.push(CodeItem::new(&i.0, i.1.clone()));
        }
        else {
            // recursively process children of a code element
            fn process_kids(item: &mut CodeItem, depth: u8, name: &str, attribs: &Vec<(String, String)>) {
                if depth > 1 { process_kids(item.children.last_mut().unwrap(), depth-1, name, attribs); }
                else         { item.children.push(CodeItem::new(name, attribs.clone())); }
            }

            let mut parent = raw_code.elements.last_mut().unwrap();
            process_kids(parent, i.2, &i.0, &i.1);
        }
    }

    raw_code
}
<commit_msg>debug formatting fix<commit_after>use std::fmt;
use std::collections::HashMap;
use fmt_code::{FormattedCode, Lang};
use string_gen::keywords::{NAME, TYPE, VALUE};

// (element name, attributes (Vec<name, value>), depth in API file structure)
pub type CodeData = (String, Vec<(String, String)>, u8);

#[derive(Clone)]
pub struct CodeItem {
    pub name: String,
    pub attributes: Vec<(String, String)>,
    pub children: Vec<CodeItem>
}

impl CodeItem {
    pub fn new(item_name: &str, item_attribs: Vec<(String, String)>) -> CodeItem {
        CodeItem {
            name: String::from(item_name),
            attributes: item_attribs,
            children: Vec::<CodeItem>::new()
        }
    }
}

pub struct CodeConfig {
    pub name: String,
    pub type_dict: HashMap<String, String>,
    pub name_dict: HashMap<String, String>,
    pub global_cfg: HashMap<String, String>
}

impl CodeConfig {
    pub fn new(cfg_name: &str) -> CodeConfig {
        CodeConfig {
            name: String::from(cfg_name),
            type_dict: HashMap::<String, String>::new(),
            name_dict: HashMap::<String, String>::new(),
            global_cfg: HashMap::<String, String>::new()
        }
    }
}

pub struct RawCode {
    pub configs: HashMap<String, CodeConfig>,
    pub elements: Vec<CodeItem>,
    supported_langs: HashMap<Lang, String>
}

impl RawCode {
    pub fn new() -> RawCode {
        let mut rc = RawCode {
            configs: HashMap::<String, CodeConfig>::new(),
            elements: Vec::<CodeItem>::new(),
            supported_langs: HashMap::<Lang, String>::new()
        };

        rc.supported_langs.insert(Lang::Cpp, String::from("cpp"));
        rc.supported_langs.insert(Lang::Rust, String::from("rust"));

        rc
    }

    // convert raw data to cpp code
    pub fn to_cpp(&self) -> FormattedCode {
        self.to_lang(Lang::Cpp)
    }
    // convert raw data to Rust code
    pub fn to_rust(&self) -> FormattedCode {
        self.to_lang(Lang::Rust)
    }

    fn to_lang(&self, lang: Lang) -> FormattedCode {
        let lang_idx = self.supported_langs.get(&lang).unwrap();
        FormattedCode::new(lang, &self.configs.get(lang_idx), &self.elements)
    }
}

impl fmt::Display for RawCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let _ = write!(f, "<raw data>\n");
        let _ = write!(f, "*\n");
        for e in self.elements.iter() {
            let mut empty_spaces = Vec::<u8>::new();
            print_code_item(e, f, 0, &mut empty_spaces);
        }
        write!(f, "*\n")
    }
}

impl fmt::Display for CodeConfig {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let _ = write!(f, "Config: {}\n", self.name);
        if self.global_cfg.len() > 0 {
            let _ = write!(f, "Settings:\n");
        }
        for (k, v) in &self.global_cfg {
            let _ = write!(f, "  {} = {}\n", k, v);
        }
        if self.name_dict.len() > 0 {
            let _ = write!(f, "Names:\n");
        }
        for (k, v) in &self.name_dict {
            let _ = write!(f, "  {} = {}\n", k, v);
        }
        if self.type_dict.len() > 0 {
            let _ = write!(f, "Types:\n");
        }
        for (k, v) in &self.type_dict {
            let _ = write!(f, "  {} = {}\n", k, v);
        }
        write!(f, "")
    }
}

// used by Display trait to print the tree of elements
pub fn print_code_item(e: &CodeItem, f: &mut fmt::Formatter, depth: u8, empty_spaces: &mut Vec<u8>) {
    // indentation
    for i in 0..depth {
        let mut separator = "|";
        for j in empty_spaces.iter() {
            if i == *j {
                separator = " ";
                break;
            }
        }
        let _ = write!(f, "{}  ", separator);
    }

    let _ = write!(f, "|--{}", e.name);
    // print attributes
    if e.attributes.len() > 0 {
        let _ = write!(f, " [");
        for a in 0..e.attributes.len() {
            if a > 0 && a < e.attributes.len() {
                let _ = write!(f, ", ");
            }
            let _ = write!(f, "{}:\"{}\"", e.attributes[a].0, e.attributes[a].1);
        }
        let _ = write!(f, "]");
    }
    let _ = write!(f, "\n");

    // child processing
    if e.children.len() > 0 {
        for c in 0..e.children.len() {
            if (e.children.len() - c) == 1 {
                empty_spaces.push(depth+1);
            }
            else {
                empty_spaces.sort();
                let idx = empty_spaces.binary_search(&(depth+1));
                match idx { Ok(_) => { empty_spaces.remove(idx.unwrap()); }, _ => {} };
            }
            print_code_item(&e.children[c], f, depth+1, empty_spaces);
        }

        // reset space directory when topmost child is reached
        if depth == 1 {
            empty_spaces.clear();
        }
    }
}

// create RawCode element from pre-parsed data
pub fn generate_raw(data: &Vec<CodeData>, config_data: &Vec<CodeData>) -> RawCode {
    let mut raw_code = RawCode::new();

    for i in config_data.iter() {
        if !raw_code.configs.contains_key(&i.0) {
            raw_code.configs.insert(i.0.clone(), CodeConfig::new(&i.0));
        }

        let mut n = String::new();
        let mut t = String::new();
        let mut v = String::new();
        // process all config attributes
        for j in i.1.iter() {
            match j.0.as_str() {
                NAME  => n = j.1.clone(),
                TYPE  => t = j.1.clone(),
                VALUE => v = j.1.clone(),
                _ => { raw_code.configs.get_mut(&i.0).unwrap().global_cfg.insert(j.0.clone(), j.1.clone()); }
            }
        }

        if n.len() > 0 {
            assert!(raw_code.configs.get_mut(&i.0).unwrap().name_dict.insert(n.clone(), v.clone()) == None, "Name \"{}\" already defined in config! (duplicate: {}={})", n, n, v);
        }
        if t.len() > 0 {
            assert!(raw_code.configs.get_mut(&i.0).unwrap().type_dict.insert(t.clone(), v.clone()) == None, "Type \"{}\" already defined in config! (duplicate: {}={}", t, t, v);
        }
    }

    for i in data.iter() {
        // if at depth 0, it's a root element, so add it to the main list
        if i.2 == 0 {
            raw_code.elements.push(CodeItem::new(&i.0, i.1.clone()));
        }
        else {
            // recursively process children of a code element
            fn process_kids(item: &mut CodeItem, depth: u8, name: &str, attribs: &Vec<(String, String)>) {
                if depth > 1 { process_kids(item.children.last_mut().unwrap(), depth-1, name, attribs); }
                else         { item.children.push(CodeItem::new(name, attribs.clone())); }
            }

            let mut parent = raw_code.elements.last_mut().unwrap();
            process_kids(parent, i.2, &i.0, &i.1);
        }
    }

    raw_code
}
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use types::gpointer;
use wrap::Wrapper;

use std::mem;
use std::ops::{Deref, DerefMut};

pub type RefFunc = unsafe extern "C" fn(gpointer) -> gpointer;
pub type UnrefFunc = unsafe extern "C" fn(gpointer);
pub type RefcountFuncs = (*const RefFunc, *const UnrefFunc);

pub trait Refcount {
    fn refcount_funcs(&self) -> &'static RefcountFuncs;
}

pub struct Ref<T: Refcount> {
    plumbing: RefImpl
}

pub struct SyncRef<T: Refcount + Send + Sync> {
    plumbing: RefImpl
}

unsafe impl<T> Send for SyncRef<T> where T: Refcount + Send + Sync { }
unsafe impl<T> Sync for SyncRef<T> where T: Refcount + Send + Sync { }

impl<T> Ref<T> where T: Refcount {

    pub fn new(source: &mut T) -> Ref<T> {
        new_ref(source)
    }
}

impl<T> Ref<T> where T: Refcount + Wrapper {

    pub unsafe fn from_raw(ptr: *mut <T as Wrapper>::Raw) -> Ref<T> {
        Ref {
            plumbing: RefImpl { ptr: ptr as gpointer }
        }
    }
}

impl<T> SyncRef<T> where T: Refcount + Send + Sync {

    pub fn new(source: &mut T) -> SyncRef<T> {
        new_sync_ref(source)
    }
}

impl<T> SyncRef<T> where T: Refcount + Wrapper + Send + Sync {

    pub unsafe fn from_raw(ptr: *mut <T as Wrapper>::Raw) -> SyncRef<T> {
        SyncRef {
            plumbing: RefImpl { ptr: ptr as gpointer }
        }
    }
}

struct RefImpl {
    ptr: gpointer
}

impl RefImpl {

    unsafe fn impl_drop(&mut self, (_, dec_ref): RefcountFuncs) {
        (*dec_ref)(self.ptr);
    }

    unsafe fn impl_clone_from(&mut self, source: &RefImpl,
                              (inc_ref, dec_ref): RefcountFuncs)
    {
        if self.ptr == source.ptr {
            return;
        }
        (*inc_ref)(source.ptr);
        (*dec_ref)(self.ptr);
        self.ptr = source.ptr;
    }
}

unsafe fn new_ref_impl(p: gpointer, (inc_ref, _): RefcountFuncs) -> RefImpl {
    (*inc_ref)(p);
    RefImpl { ptr: p }
}

fn new_ref<T>(source: &T) -> Ref<T>
    where T: Refcount
{
    let p = source as *const T as gpointer;
    let funcs = source.refcount_funcs();
    Ref {
        plumbing: unsafe { new_ref_impl(p, *funcs) }
    }
}

fn new_sync_ref<T>(source: &T) -> SyncRef<T>
    where T: Refcount + Send + Sync
{
    let p = source as *const T as gpointer;
    let funcs = source.refcount_funcs();
    SyncRef {
        plumbing: unsafe { new_ref_impl(p, *funcs) }
    }
}

#[unsafe_destructor]
impl<T> Drop for Ref<T> where T: Refcount {
    fn drop(&mut self) {
        let funcs = self.refcount_funcs();
        unsafe {
            self.plumbing.impl_drop(*funcs);
        }
    }
}

#[unsafe_destructor]
impl<T> Drop for SyncRef<T> where T: Refcount + Send + Sync {
    fn drop(&mut self) {
        let funcs = self.refcount_funcs();
        unsafe {
            self.plumbing.impl_drop(*funcs);
        }
    }
}

impl<T: Refcount> Clone for Ref<T> {

    fn clone(&self) -> Ref<T> {
        new_ref(self.deref())
    }

    fn clone_from(&mut self, source: &Ref<T>) {
        let funcs = self.refcount_funcs();
        unsafe {
            self.plumbing.impl_clone_from(&source.plumbing, *funcs);
        }
    }
}

impl<T: Refcount + Send + Sync> Clone for SyncRef<T> {

    fn clone(&self) -> SyncRef<T> {
        new_sync_ref(self.deref())
    }

    fn clone_from(&mut self, source: &SyncRef<T>) {
        let funcs = self.refcount_funcs();
        unsafe {
            self.plumbing.impl_clone_from(&source.plumbing, *funcs);
        }
    }
}

impl<T> Deref for Ref<T> where T: Refcount {

    type Target = T;

    fn deref(&self) -> &T {
        let p = self.plumbing.ptr as *const T;
        unsafe { mem::copy_lifetime(self, &*p) }
    }
}

impl<T> Deref for SyncRef<T> where T: Refcount + Send + Sync {

    type Target = T;

    fn deref(&self) -> &T {
        let p = self.plumbing.ptr as *const T;
        unsafe { mem::copy_lifetime(self, &*p) }
    }
}

impl<T> DerefMut for Ref<T> where T: Refcount {

    fn deref_mut(&mut self) -> &mut T {
        let p = self.plumbing.ptr as *mut T;
        unsafe { mem::copy_mut_lifetime(self, &mut *p) }
    }
}

impl<T> DerefMut for SyncRef<T> where T: Refcount + Send + Sync {

    fn deref_mut(&mut self) -> &mut T {
        let p = self.plumbing.ptr as *mut T;
        unsafe { mem::copy_mut_lifetime(self, &mut *p) }
    }
}
<commit_msg>refcount: Refurbish<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use types::gpointer;
use wrap::Wrapper;

use std::mem;
use std::ops::{Deref, DerefMut};

pub type RefFunc = unsafe extern "C" fn(gpointer) -> gpointer;
pub type UnrefFunc = unsafe extern "C" fn(gpointer);
pub type RefcountFuncs = (*const RefFunc, *const UnrefFunc);

pub trait Refcount {
    fn refcount_funcs(&self) -> &'static RefcountFuncs;
}

pub struct Ref<T> where T: Refcount {
    plumbing: RefImpl
}

pub struct SyncRef<T> where T: Refcount {
    plumbing: RefImpl
}

unsafe impl<T> Send for SyncRef<T> where T: Refcount + Send + Sync { }
unsafe impl<T> Sync for SyncRef<T> where T: Refcount + Send + Sync { }

impl<T> Ref<T> where T: Refcount {

    pub fn new(source: &T) -> Ref<T> {
        let p = source as *const T as gpointer;
        let funcs = source.refcount_funcs();
        Ref {
            plumbing: unsafe { RefImpl::new(p, funcs) }
        }
    }
}

impl<T> Ref<T> where T: Refcount + Wrapper {

    pub unsafe fn from_raw(ptr: *mut <T as Wrapper>::Raw) -> Ref<T> {
        Ref {
            plumbing: RefImpl { ptr: ptr as gpointer }
        }
    }
}

impl<T> SyncRef<T> where T: Refcount + Send + Sync {

    pub fn new(source: &T) -> SyncRef<T> {
        let p = source as *const T as gpointer;
        let funcs = source.refcount_funcs();
        SyncRef {
            plumbing: unsafe { RefImpl::new(p, funcs) }
        }
    }
}

impl<T> SyncRef<T> where T: Refcount + Wrapper + Send + Sync {

    pub unsafe fn from_raw(ptr: *mut <T as Wrapper>::Raw) -> SyncRef<T> {
        SyncRef {
            plumbing: RefImpl { ptr: ptr as gpointer }
        }
    }
}

struct RefImpl {
    ptr: gpointer
}

impl RefImpl {

    unsafe fn new(p: gpointer, funcs: &RefcountFuncs) -> RefImpl {
        let (inc_ref, _) = *funcs;
        (*inc_ref)(p);
        RefImpl { ptr: p }
    }

    unsafe fn impl_drop(&mut self, funcs: &RefcountFuncs) {
        let (_, dec_ref) = *funcs;
        (*dec_ref)(self.ptr);
    }

    unsafe fn impl_clone_from(&mut self,
                              source: &RefImpl,
                              funcs: &RefcountFuncs)
    {
        let (inc_ref, dec_ref) = *funcs;
        (*inc_ref)(source.ptr);
        (*dec_ref)(self.ptr);
        self.ptr = source.ptr;
    }
}

#[unsafe_destructor]
impl<T> Drop for Ref<T> where T: Refcount {
    fn drop(&mut self) {
        let funcs = self.refcount_funcs();
        unsafe {
            self.plumbing.impl_drop(funcs);
        }
    }
}

#[unsafe_destructor]
impl<T> Drop for SyncRef<T> where T: Refcount {
    fn drop(&mut self) {
        let funcs = self.refcount_funcs();
        unsafe {
            self.plumbing.impl_drop(funcs);
        }
    }
}

impl<T> Clone for Ref<T> where T: Refcount {

    fn clone(&self) -> Ref<T> {
        Ref::new(self.deref())
    }

    fn clone_from(&mut self, source: &Ref<T>) {
        let funcs = self.refcount_funcs();
        unsafe {
            self.plumbing.impl_clone_from(&source.plumbing, funcs);
        }
    }
}

impl<T> Clone for SyncRef<T> where T: Refcount + Send + Sync {

    fn clone(&self) -> SyncRef<T> {
        SyncRef::new(self.deref())
    }

    fn clone_from(&mut self, source: &SyncRef<T>) {
        let funcs = self.refcount_funcs();
        unsafe {
            self.plumbing.impl_clone_from(&source.plumbing, funcs);
        }
    }
}

impl<T> Deref for Ref<T> {

    type Target = T;

    fn deref(&self) -> &T {
        let p = self.plumbing.ptr as *const T;
        unsafe { mem::copy_lifetime(self, &*p) }
    }
}

impl<T> Deref for SyncRef<T> {

    type Target = T;

    fn deref(&self) -> &T {
        let p = self.plumbing.ptr as *const T;
        unsafe { mem::copy_lifetime(self, &*p) }
    }
}

impl<T> DerefMut for Ref<T> {

    fn deref_mut(&mut self) -> &mut T {
        let p = self.plumbing.ptr as *mut T;
        unsafe { mem::copy_mut_lifetime(self, &mut *p) }
    }
}

impl<T> DerefMut for SyncRef<T> {

    fn deref_mut(&mut self) -> &mut T {
        let p = self.plumbing.ptr as *mut T;
        unsafe { mem::copy_mut_lifetime(self, &mut *p) }
    }
}
<|endoftext|>


<commit_before>
use super::effective_address;
use super::{Core, Result};

pub fn ea_ay_pd_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = effective_address::predecrement_ay_8(core);
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_ax_pd_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = effective_address::predecrement_ax_8(core);
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_ay_pi_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = effective_address::postincrement_ay_8(core);
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_ay_ai_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = effective_address::address_indirect_ay(core);
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_ay_di_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = try!(effective_address::displacement_ay(core));
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_ay_ix_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = try!(effective_address::index_ay(core));
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_aw_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = try!(effective_address::absolute_word(core));
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_al_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = try!(effective_address::absolute_long(core));
	core.read_data_byte(ea).map(|val| (val, ea))
}

pub fn ay_pd_8(core: &mut Core) -> Result<u32> {
	let ea = effective_address::predecrement_ay_8(core);
	core.read_data_byte(ea)
}
pub fn ay_pi_8(core: &mut Core) -> Result<u32> {
	let ea = effective_address::postincrement_ay_8(core);
	core.read_data_byte(ea)
}
pub fn ay_ai_8(core: &mut Core) -> Result<u32> {
	let ea = effective_address::address_indirect_ay(core);
	core.read_data_byte(ea)
}
pub fn ay_di_8(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::displacement_ay(core));
	core.read_data_byte(ea)
}
pub fn ay_ix_8(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::index_ay(core));
	core.read_data_byte(ea)
}
pub fn aw_8(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::absolute_word(core));
	core.read_data_byte(ea)
}
pub fn al_8(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::absolute_long(core));
	core.read_data_byte(ea)
}
pub fn pcdi_8(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::displacement_pc(core));
	core.read_program_byte(ea)
}
pub fn pcix_8(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::index_pc(core));
	core.read_program_byte(ea)
}
pub fn imm_8(core: &mut Core) -> Result<u32> {
	let extension = try!(core.read_imm_u16());
	Ok(mask_out_above_8!(extension) as u32)
}
pub fn ay_pd_16(core: &mut Core) -> Result<u32> {
	let ea = effective_address::predecrement_ay_16(core);
	core.read_data_word(ea)
}
pub fn ay_pi_16(core: &mut Core) -> Result<u32> {
	let ea = effective_address::postincrement_ay_16(core);
	core.read_data_word(ea)
}
pub fn ay_ai_16(core: &mut Core) -> Result<u32> {
	let ea = effective_address::address_indirect_ay(core);
	core.read_data_word(ea)
}
pub fn ay_di_16(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::displacement_ay(core));
	core.read_data_word(ea)
}
pub fn ay_ix_16(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::index_ay(core));
	core.read_data_word(ea)
}
pub fn aw_16(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::absolute_word(core));
	core.read_data_word(ea)
}
pub fn al_16(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::absolute_long(core));
	core.read_data_word(ea)
}
pub fn pcdi_16(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::displacement_pc(core));
	core.read_program_word(ea)
}
pub fn pcix_16(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::index_pc(core));
	core.read_program_word(ea)
}
pub fn imm_16(core: &mut Core) -> Result<u32> {
	let extension = try!(core.read_imm_i16());
	Ok(extension as u32)
}
pub fn ay_pd_32(core: &mut Core) -> Result<u32> {
	let ea = effective_address::predecrement_ay_32(core);
	core.read_data_long(ea)
}
pub fn ay_pi_32(core: &mut Core) -> Result<u32> {
	let ea = effective_address::postincrement_ay_32(core);
	core.read_data_long(ea)
}
pub fn ay_ai_32(core: &mut Core) -> Result<u32> {
	let ea = effective_address::address_indirect_ay(core);
	core.read_data_long(ea)
}
pub fn ay_di_32(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::displacement_ay(core));
	core.read_data_long(ea)
}
pub fn ay_ix_32(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::index_ay(core));
	core.read_data_long(ea)
}
pub fn aw_32(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::absolute_word(core));
	core.read_data_long(ea)
}
pub fn al_32(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::absolute_long(core));
	core.read_data_long(ea)
}
pub fn pcdi_32(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::displacement_pc(core));
	core.read_program_long(ea)
}
pub fn pcix_32(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::index_pc(core));
	core.read_program_long(ea)
}
pub fn imm_32(core: &mut Core) -> Result<u32> {
	let extension = try!(core.read_imm_u32());
	Ok(extension)
}
pub fn dx(core: &mut Core) -> Result<u32> {
	Ok(dx!(core))
}
pub fn dy(core: &mut Core) -> Result<u32> {
	Ok(dy!(core))
}
pub fn ay(core: &mut Core) -> Result<u32> {
	Ok(ay!(core))
}
#[cfg(test)]
mod tests {
	use super::super::Core;
	use super::super::Exception::AddressError;
	use super::{ea_ax_pd_8, ay_pd_8, ay_ai_16};
	use ram::{AddressBus, SUPERVISOR_DATA};

	#[test]
	fn test_ax_predecrement_8() {
		let mut core = Core::new(0x40);
		for i in 0..8 {
			let addr: u32 = 0x200 + 4*i;
			core.dar[8+i as usize] = addr;
			// write just before where A0-A7 points
			let adjustment = if i == 7 {2} else {1};
			core.mem.write_byte(SUPERVISOR_DATA, addr - adjustment, 0x11*i);
		}
		core.ir = 0b1111_1001_1111_1010; // X=4, Y=2
		let core = &mut core;

		assert_eq!(512+4*4, core.dar[8+4]);
		let (dst, ea) = ea_ax_pd_8(core).unwrap();
		assert_eq!(0x44, dst);
		assert_eq!(512+4*4-1, core.dar[8+4]);
		assert_eq!(512+4*4-1, ea);

		core.ir = 0b1111_1111_1111_1111; // X=7, Y=7
		assert_eq!(512+4*7, core.dar[8+7]);
		let (dst, ea) = ea_ax_pd_8(core).unwrap();
		assert_eq!(0x77, dst);
		// A7 is kept even
		assert_eq!(512+4*7-2, core.dar[8+7]);
		assert_eq!(512+4*7-2, ea);
	}
	#[test]
	fn test_ay_predecrement_8() {
		let mut core = Core::new(0x40);
		for i in 0..8 {
			let addr: u32 = 0x200 + 4*i;
			core.dar[8+i as usize] = addr;
			// write just before where A0-A7 points
			let adjustment = if i == 7 {2} else {1};
			core.mem.write_byte(SUPERVISOR_DATA, addr - adjustment, 0x11*i);
		}

		core.ir = 0b1111_1001_1111_1010; // X=4, Y=2
		let core = &mut core;
		assert_eq!(512+4*2, core.dar[8+2]);
		assert_eq!(0x22, ay_pd_8(core).unwrap());
		assert_eq!(512+4*2-1, core.dar[8+2]);

		core.ir = 0b1111_1011_1111_1111; // X=5, Y=7
		assert_eq!(512+4*7, core.dar[8+7]);
		assert_eq!(0x77, ay_pd_8(core).unwrap());
		// A7 is kept even
		assert_eq!(512+4*7-2, core.dar[8+7]);
	}
	#[test]
	fn test_address_error_on_odd_addresses() {
		let mut core = Core::new(0x40);
		core.dar[8] = 0x11; // odd address
		core.ir = 0b1111_1001_1111_1000; // X=4, Y=0
		match ay_ai_16(&mut core) {
			Err(AddressError{..}) => (), // good!
			_ => panic!("Unexpected"),
		};
	}
	#[test]
	fn test_no_address_error_on_even_addresses() {
		let mut core = Core::new(0x40);
		core.dar[8] = 0x12; // even address
		core.ir = 0b1111_1001_1111_1000; // X=4, Y=0
		match ay_ai_16(&mut core) {
			Ok(_) => (), // good!
			_ => panic!("Unexpected"),
		};
	}
}
<commit_msg>Add 16-bit versions of ea-returning operators<commit_after>
use super::effective_address;
use super::{Core, Result};

pub fn ea_ay_pd_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = effective_address::predecrement_ay_8(core);
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_ax_pd_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = effective_address::predecrement_ax_8(core);
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_ay_pi_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = effective_address::postincrement_ay_8(core);
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_ay_ai_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = effective_address::address_indirect_ay(core);
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_ay_di_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = try!(effective_address::displacement_ay(core));
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_ay_ix_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = try!(effective_address::index_ay(core));
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_aw_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = try!(effective_address::absolute_word(core));
	core.read_data_byte(ea).map(|val| (val, ea))
}
pub fn ea_al_8(core: &mut Core) -> Result<(u32, u32)> {
	let ea = try!(effective_address::absolute_long(core));
	core.read_data_byte(ea).map(|val| (val, ea))
}

pub fn ay_pd_8(core: &mut Core) -> Result<u32> {
	let ea = effective_address::predecrement_ay_8(core);
	core.read_data_byte(ea)
}
pub fn ay_pi_8(core: &mut Core) -> Result<u32> {
	let ea = effective_address::postincrement_ay_8(core);
	core.read_data_byte(ea)
}
pub fn ay_ai_8(core: &mut Core) -> Result<u32> {
	let ea = effective_address::address_indirect_ay(core);
	core.read_data_byte(ea)
}
pub fn ay_di_8(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::displacement_ay(core));
	core.read_data_byte(ea)
}
pub fn ay_ix_8(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::index_ay(core));
	core.read_data_byte(ea)
}
pub fn aw_8(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::absolute_word(core));
	core.read_data_byte(ea)
}
pub fn al_8(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::absolute_long(core));
	core.read_data_byte(ea)
}
pub fn pcdi_8(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::displacement_pc(core));
	core.read_program_byte(ea)
}
pub fn pcix_8(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::index_pc(core));
	core.read_program_byte(ea)
}
pub fn imm_8(core: &mut Core) -> Result<u32> {
	let extension = try!(core.read_imm_u16());
	Ok(mask_out_above_8!(extension) as u32)
}

pub fn ea_ay_pd_16(core: &mut Core) -> Result<(u32, u32)> {
	let ea = effective_address::predecrement_ay_16(core);
	core.read_data_word(ea).map(|val| (val, ea))
}
pub fn ea_ay_pi_16(core: &mut Core) -> Result<(u32, u32)> {
	let ea = effective_address::postincrement_ay_16(core);
	core.read_data_word(ea).map(|val| (val, ea))
}
pub fn ea_ay_ai_16(core: &mut Core) -> Result<(u32, u32)> {
	let ea = effective_address::address_indirect_ay(core);
	core.read_data_word(ea).map(|val| (val, ea))
}
pub fn ea_ay_di_16(core: &mut Core) -> Result<(u32, u32)> {
	let ea = try!(effective_address::displacement_ay(core));
	core.read_data_word(ea).map(|val| (val, ea))
}
pub fn ea_ay_ix_16(core: &mut Core) -> Result<(u32, u32)> {
	let ea = try!(effective_address::index_ay(core));
	core.read_data_word(ea).map(|val| (val, ea))
}
pub fn ea_aw_16(core: &mut Core) -> Result<(u32, u32)> {
	let ea = try!(effective_address::absolute_word(core));
	core.read_data_word(ea).map(|val| (val, ea))
}
pub fn ea_al_16(core: &mut Core) -> Result<(u32, u32)> {
	let ea = try!(effective_address::absolute_long(core));
	core.read_data_word(ea).map(|val| (val, ea))
}

pub fn ay_pd_16(core: &mut Core) -> Result<u32> {
	let ea = effective_address::predecrement_ay_16(core);
	core.read_data_word(ea)
}
pub fn ay_pi_16(core: &mut Core) -> Result<u32> {
	let ea = effective_address::postincrement_ay_16(core);
	core.read_data_word(ea)
}
pub fn ay_ai_16(core: &mut Core) -> Result<u32> {
	let ea = effective_address::address_indirect_ay(core);
	core.read_data_word(ea)
}
pub fn ay_di_16(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::displacement_ay(core));
	core.read_data_word(ea)
}
pub fn ay_ix_16(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::index_ay(core));
	core.read_data_word(ea)
}
pub fn aw_16(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::absolute_word(core));
	core.read_data_word(ea)
}
pub fn al_16(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::absolute_long(core));
	core.read_data_word(ea)
}
pub fn pcdi_16(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::displacement_pc(core));
	core.read_program_word(ea)
}
pub fn pcix_16(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::index_pc(core));
	core.read_program_word(ea)
}
pub fn imm_16(core: &mut Core) -> Result<u32> {
	let extension = try!(core.read_imm_i16());
	Ok(extension as u32)
}
pub fn ay_pd_32(core: &mut Core) -> Result<u32> {
	let ea = effective_address::predecrement_ay_32(core);
	core.read_data_long(ea)
}
pub fn ay_pi_32(core: &mut Core) -> Result<u32> {
	let ea = effective_address::postincrement_ay_32(core);
	core.read_data_long(ea)
}
pub fn ay_ai_32(core: &mut Core) -> Result<u32> {
	let ea = effective_address::address_indirect_ay(core);
	core.read_data_long(ea)
}
pub fn ay_di_32(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::displacement_ay(core));
	core.read_data_long(ea)
}
pub fn ay_ix_32(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::index_ay(core));
	core.read_data_long(ea)
}
pub fn aw_32(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::absolute_word(core));
	core.read_data_long(ea)
}
pub fn al_32(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::absolute_long(core));
	core.read_data_long(ea)
}
pub fn pcdi_32(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::displacement_pc(core));
	core.read_program_long(ea)
}
pub fn pcix_32(core: &mut Core) -> Result<u32> {
	let ea = try!(effective_address::index_pc(core));
	core.read_program_long(ea)
}
pub fn imm_32(core: &mut Core) -> Result<u32> {
	let extension = try!(core.read_imm_u32());
	Ok(extension)
}
pub fn dx(core: &mut Core) -> Result<u32> {
	Ok(dx!(core))
}
pub fn dy(core: &mut Core) -> Result<u32> {
	Ok(dy!(core))
}
pub fn ay(core: &mut Core) -> Result<u32> {
	Ok(ay!(core))
}
#[cfg(test)]
mod tests {
	use super::super::Core;
	use super::super::Exception::AddressError;
	use super::{ea_ax_pd_8, ay_pd_8, ay_ai_16};
	use ram::{AddressBus, SUPERVISOR_DATA};

	#[test]
	fn test_ax_predecrement_8() {
		let mut core = Core::new(0x40);
		for i in 0..8 {
			let addr: u32 = 0x200 + 4*i;
			core.dar[8+i as usize] = addr;
			// write just before where A0-A7 points
			let adjustment = if i == 7 {2} else {1};
			core.mem.write_byte(SUPERVISOR_DATA, addr - adjustment, 0x11*i);
		}
		core.ir = 0b1111_1001_1111_1010; // X=4, Y=2
		let core = &mut core;

		assert_eq!(512+4*4, core.dar[8+4]);
		let (dst, ea) = ea_ax_pd_8(core).unwrap();
		assert_eq!(0x44, dst);
		assert_eq!(512+4*4-1, core.dar[8+4]);
		assert_eq!(512+4*4-1, ea);

		core.ir = 0b1111_1111_1111_1111; // X=7, Y=7
		assert_eq!(512+4*7, core.dar[8+7]);
		let (dst, ea) = ea_ax_pd_8(core).unwrap();
		assert_eq!(0x77, dst);
		// A7 is kept even
		assert_eq!(512+4*7-2, core.dar[8+7]);
		assert_eq!(512+4*7-2, ea);
	}
	#[test]
	fn test_ay_predecrement_8() {
		let mut core = Core::new(0x40);
		for i in 0..8 {
			let addr: u32 = 0x200 + 4*i;
			core.dar[8+i as usize] = addr;
			// write just before where A0-A7 points
			let adjustment = if i == 7 {2} else {1};
			core.mem.write_byte(SUPERVISOR_DATA, addr - adjustment, 0x11*i);
		}

		core.ir = 0b1111_1001_1111_1010; // X=4, Y=2
		let core = &mut core;
		assert_eq!(512+4*2, core.dar[8+2]);
		assert_eq!(0x22, ay_pd_8(core).unwrap());
		assert_eq!(512+4*2-1, core.dar[8+2]);

		core.ir = 0b1111_1011_1111_1111; // X=5, Y=7
		assert_eq!(512+4*7, core.dar[8+7]);
		assert_eq!(0x77, ay_pd_8(core).unwrap());
		// A7 is kept even
		assert_eq!(512+4*7-2, core.dar[8+7]);
	}
	#[test]
	fn test_address_error_on_odd_addresses() {
		let mut core = Core::new(0x40);
		core.dar[8] = 0x11; // odd address
		core.ir = 0b1111_1001_1111_1000; // X=4, Y=0
		match ay_ai_16(&mut core) {
			Err(AddressError{..}) => (), // good!
			_ => panic!("Unexpected"),
		};
	}
	#[test]
	fn test_no_address_error_on_even_addresses() {
		let mut core = Core::new(0x40);
		core.dar[8] = 0x12; // even address
		core.ir = 0b1111_1001_1111_1000; // X=4, Y=0
		match ay_ai_16(&mut core) {
			Ok(_) => (), // good!
			_ => panic!("Unexpected"),
		};
	}
}
<|endoftext|>