<commit_before>use crate::{
    buffer::Buffer, connection::Connection, connection_status::ConnectionState, Error,
    PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, trace};
use mio::{event::Source, Events, Interest, Poll, Token, Waker};
use std::{
    collections::VecDeque,
    io::{Read, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::{Duration, Instant},
};

pub(crate) const SOCKET: Token = Token(1);
const WAKER: Token = Token(2);

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    Setup,
    Stop,
}

pub struct IoLoop<T> {
    connection: Connection,
    socket: T,
    status: Status,
    poll: Poll,
    waker: Arc<Waker>,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    can_write: bool,
    can_read: bool,
    poll_timeout: Option<Duration>,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
    last_write: Instant,
}

impl<T: Source + Read + Write + Send + 'static> IoLoop<T> {
    pub(crate) fn new(
        connection: Connection,
        socket: T,
        poll: Option<(Poll, Token)>,
    ) -> Result<Self> {
        let (poll, registered) = poll
            .map(|t| Ok((t.0, true)))
            .unwrap_or_else(|| Poll::new().map(|poll| (poll, false)))?;
        let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
        let waker = Arc::new(Waker::new(poll.registry(), WAKER)?);
        let mut inner = Self {
            connection,
            socket,
            status: Status::Initial,
            poll,
            waker,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            can_write: false,
            can_read: false,
            poll_timeout: None,
            serialized_frames: VecDeque::default(),
            last_write: Instant::now(),
        };
        if registered {
            inner.poll.registry().reregister(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        } else {
            inner.poll.registry().register(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }
        Ok(inner)
    }

    fn ensure_setup(&mut self) -> Result<()> {
        if self.status != Status::Setup && self.connection.status().connected() {
            let frame_max = self.connection.configuration().frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.connection.configuration().heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negociated timeout)
                self.poll_timeout = Some(heartbeat);
            }
            self.status = Status::Setup;
        }
        Ok(())
    }

    fn has_data(&self) -> bool {
        self.connection.has_pending_frames()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&self) -> bool {
        self.can_write && self.has_data() && !self.connection.status().blocked()
    }

    fn can_read(&self) -> bool {
        self.can_read
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        let connection_status = self.connection.status();
        (self.status == Status::Initial
            || connection_status.connected()
            || connection_status.closing())
            && self.status != Status::Stop
            && !connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.waker.clone();
        self.connection.clone().set_io_loop(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    let mut events = Events::with_capacity(1024);
                    while self.should_continue() {
                        if let Err(err) = self.run(&mut events) {
                            self.cancel_serilized_frames(err)?;
                        }
                    }
                    Ok(())
                })?,
            waker,
        )
    }

    fn cancel_serilized_frames(&self, error: Error) -> Result<()> {
        for (_, resolver) in self.serialized_frames.iter() {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn poll_timeout(&self) -> Option<Duration> {
        self.poll_timeout.map(|timeout| {
            timeout
                .checked_sub(self.last_write.elapsed())
                .unwrap_or_else(|| Duration::from_secs(0))
        })
    }

    fn poll(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop poll");
        self.poll.poll(events, self.poll_timeout())?;
        trace!("io_loop poll done");
        for event in events.iter() {
            if event.token() == SOCKET {
                if event.is_readable() {
                    self.can_read = true;
                }
                if event.is_writable() {
                    self.can_write = true;
                }
            }
        }
        Ok(())
    }

    fn run(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop run");
        self.ensure_setup()?;
        self.poll(events)?;
        self.do_run()
    }

    fn do_run(&mut self) -> Result<()> {
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.can_read,
            self.can_write,
            self.has_data()
        );
        loop {
            self.write()?;
            if self.connection.status().closed() {
                self.status = Status::Stop;
            }
            if self.should_continue() {
                self.read()?;
            }
            self.parse()?;
            self.connection.poll_internal_promises()?;
            if self.should_heartbeat() {
                self.connection.send_heartbeat()?;
                // Update last_write so that if we cannot write yet to the socket, we don't enqueue countless heartbeats
                self.last_write = Instant::now();
            }
            if self.stop_looping() {
                self.maybe_continue()?;
                break;
            }
        }
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.can_read,
            self.can_write,
            self.has_data(),
            self.status
        );
        Ok(())
    }

    fn should_heartbeat(&self) -> bool {
        if let Some(heartbeat_timeout) = self.poll_timeout {
            self.last_write.elapsed() > heartbeat_timeout
        } else {
            false
        }
    }

    fn stop_looping(&self) -> bool {
        !self.can_read()
            || !self.can_write()
            || self.status == Status::Stop
            || self.connection.status().errored()
    }

    fn has_pending_operations(&self) -> bool {
        self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write())
    }

    fn maybe_continue(&mut self) -> Result<()> {
        if self.has_pending_operations() {
            trace!(
                "io_loop send continue; can_read={}, can_write={}, has_data={}",
                self.can_read,
                self.can_write,
                self.has_data()
            );
            self.send_continue()?;
        }
        Ok(())
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let ConnectionState::SentProtocolHeader(resolver, ..) = self.connection.status().state()
        {
            resolver.swear(Err(error.clone()));
            self.status = Status::Stop;
        }
        self.connection.set_error(error.clone())?;
        Err(error)
    }

    fn write(&mut self) -> Result<()> {
        if self.can_write() {
            if let Err(e) = self.write_to_stream() {
                if e.wouldblock() {
                    self.can_write = false
                } else {
                    error!("error writing: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        Ok(())
    }

    fn read(&mut self) -> Result<()> {
        if self.can_read() {
            if let Err(e) = self.read_from_stream() {
                if e.wouldblock() {
                    self.can_read = false
                } else {
                    error!("error reading: {:?}", e);
                    self.critical_error(e)?;
                }
            }
            self.receive_buffer.shift_unless_available(self.frame_size);
        }
        Ok(())
    }

    fn send_continue(&mut self) -> Result<()> {
        self.waker.wake()?;
        Ok(())
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.socket)?;

        if sz > 0 {
            self.last_write = Instant::now();

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz, true);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                self.send_continue()?;
            }
        }
        Ok(())
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection.status().state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer
                    .read_from(&mut self.socket, false)
                    .map(|sz| {
                        trace!("read {} bytes", sz);
                        self.receive_buffer.fill(sz, false);
                    })?;
                Ok(())
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        if let Some((next_msg, resolver)) = self.connection.next_frame() {
            trace!("will write to buffer: {:?}", next_msg);
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => {
                    self.serialized_frames.push_back((sz, resolver));
                    Ok(())
                }
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.connection.requeue_frame((next_msg, resolver))?;
                            Ok(())
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            let error = Error::SerialisationError(Arc::new(e));
                            self.connection.set_error(error.clone())?;
                            Err(error)
                        }
                    }
                }
            }
        } else {
            Ok(())
        }
    }

    fn parse(&mut self) -> Result<()> {
        if self.can_parse() {
            if let Some(frame) = self.do_parse()? {
                self.connection.handle_frame(frame)?;
            }
        }
        Ok(())
    }

    fn do_parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.data()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                self.receive_buffer.consume(consumed, false);
                Ok(Some(f))
            }
            Err(e) => {
                if e.is_incomplete() {
                    self.receive_buffer.shift();
                    Ok(None)
                } else {
                    error!("parse error: {:?}", e);
                    let error = Error::ParsingError(e);
                    self.connection.set_error(error.clone())?;
                    Err(error)
                }
            }
        }
    }
}
<commit_msg>IoLoop: more logs, treat write of 0 as wouldblock<commit_after>use crate::{
    buffer::Buffer, connection::Connection, connection_status::ConnectionState, Error,
    PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, trace};
use mio::{event::Source, Events, Interest, Poll, Token, Waker};
use std::{
    collections::VecDeque,
    io::{Read, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::{Duration, Instant},
};

pub(crate) const SOCKET: Token = Token(1);
const WAKER: Token = Token(2);

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    Setup,
    Stop,
}

pub struct IoLoop<T> {
    connection: Connection,
    socket: T,
    status: Status,
    poll: Poll,
    waker: Arc<Waker>,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    can_write: bool,
    can_read: bool,
    poll_timeout: Option<Duration>,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
    last_write: Instant,
}

impl<T: Source + Read + Write + Send + 'static> IoLoop<T> {
    pub(crate) fn new(
        connection: Connection,
        socket: T,
        poll: Option<(Poll, Token)>,
    ) -> Result<Self> {
        let (poll, registered) = poll
            .map(|t| Ok((t.0, true)))
            .unwrap_or_else(|| Poll::new().map(|poll| (poll, false)))?;
        let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
        let waker = Arc::new(Waker::new(poll.registry(), WAKER)?);
        let mut inner = Self {
            connection,
            socket,
            status: Status::Initial,
            poll,
            waker,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            can_write: false,
            can_read: false,
            poll_timeout: None,
            serialized_frames: VecDeque::default(),
            last_write: Instant::now(),
        };
        if registered {
            inner.poll.registry().reregister(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        } else {
            inner.poll.registry().register(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }
        Ok(inner)
    }

    fn ensure_setup(&mut self) -> Result<()> {
        if self.status != Status::Setup && self.connection.status().connected() {
            let frame_max = self.connection.configuration().frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.connection.configuration().heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negociated timeout)
                self.poll_timeout = Some(heartbeat);
            }
            self.status = Status::Setup;
        }
        Ok(())
    }

    fn has_data(&self) -> bool {
        self.connection.has_pending_frames()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&self) -> bool {
        self.can_write && self.has_data() && !self.connection.status().blocked()
    }

    fn can_read(&self) -> bool {
        self.can_read
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        let connection_status = self.connection.status();
        (self.status == Status::Initial
            || connection_status.connected()
            || connection_status.closing())
            && self.status != Status::Stop
            && !connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.waker.clone();
        self.connection.clone().set_io_loop(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    let mut events = Events::with_capacity(1024);
                    while self.should_continue() {
                        if let Err(err) = self.run(&mut events) {
                            self.cancel_serilized_frames(err)?;
                        }
                    }
                    Ok(())
                })?,
            waker,
        )
    }

    fn cancel_serilized_frames(&self, error: Error) -> Result<()> {
        for (_, resolver) in self.serialized_frames.iter() {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn poll_timeout(&self) -> Option<Duration> {
        self.poll_timeout.map(|timeout| {
            timeout
                .checked_sub(self.last_write.elapsed())
                .unwrap_or_else(|| Duration::from_secs(0))
        })
    }

    fn poll(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop poll");
        self.poll.poll(events, self.poll_timeout())?;
        trace!("io_loop poll done");
        for event in events.iter() {
            if event.token() == SOCKET {
                trace!("Got mio event for socket: {:?}", event);
                if event.is_readable() {
                    self.can_read = true;
                }
                if event.is_writable() {
                    self.can_write = true;
                }
            }
        }
        Ok(())
    }

    fn run(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop run");
        self.ensure_setup()?;
        self.poll(events)?;
        self.do_run()
    }

    fn do_run(&mut self) -> Result<()> {
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.can_read,
            self.can_write,
            self.has_data()
        );
        loop {
            self.write()?;
            if self.connection.status().closed() {
                self.status = Status::Stop;
            }
            if self.should_continue() {
                self.read()?;
            }
            self.parse()?;
            self.connection.poll_internal_promises()?;
            if self.should_heartbeat() {
                self.connection.send_heartbeat()?;
                // Update last_write so that if we cannot write yet to the socket, we don't enqueue countless heartbeats
                self.last_write = Instant::now();
            }
            if self.stop_looping() {
                self.maybe_continue()?;
                break;
            }
        }
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.can_read,
            self.can_write,
            self.has_data(),
            self.status
        );
        Ok(())
    }

    fn should_heartbeat(&self) -> bool {
        if let Some(heartbeat_timeout) = self.poll_timeout {
            self.last_write.elapsed() > heartbeat_timeout
        } else {
            false
        }
    }

    fn stop_looping(&self) -> bool {
        !self.can_read()
            || !self.can_write()
            || self.status == Status::Stop
            || self.connection.status().errored()
    }

    fn has_pending_operations(&self) -> bool {
        self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write())
    }

    fn maybe_continue(&mut self) -> Result<()> {
        if self.has_pending_operations() {
            trace!(
                "io_loop send continue; can_read={}, can_write={}, has_data={}",
                self.can_read,
                self.can_write,
                self.has_data()
            );
            self.send_continue()?;
        }
        Ok(())
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let ConnectionState::SentProtocolHeader(resolver, ..) = self.connection.status().state()
        {
            resolver.swear(Err(error.clone()));
            self.status = Status::Stop;
        }
        self.connection.set_error(error.clone())?;
        Err(error)
    }

    fn write(&mut self) -> Result<()> {
        if self.can_write() {
            if let Err(e) = self.write_to_stream() {
                if e.wouldblock() {
                    self.can_write = false
                } else {
                    error!("error writing: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        Ok(())
    }

    fn read(&mut self) -> Result<()> {
        if self.can_read() {
            if let Err(e) = self.read_from_stream() {
                if e.wouldblock() {
                    self.can_read = false
                } else {
                    error!("error reading: {:?}", e);
                    self.critical_error(e)?;
                }
            }
            self.receive_buffer.shift_unless_available(self.frame_size);
        }
        Ok(())
    }

    fn send_continue(&mut self) -> Result<()> {
        self.waker.wake()?;
        Ok(())
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.socket)?;

        if sz > 0 {
            self.last_write = Instant::now();

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz, true);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        trace!("{} to write to complete this frame", to_write - written);
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    error!("We've written {} but didn't expect to write anything", written);
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                trace!("Still {} to write", self.send_buffer.available_data());
                self.send_continue()?;
            }
        } else {
            error!("Socket was writable but we wrote 0, marking as wouldblock");
            self.can_write = false;
        }
        Ok(())
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection.status().state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer
                    .read_from(&mut self.socket, false)
                    .map(|sz| {
                        trace!("read {} bytes", sz);
                        self.receive_buffer.fill(sz, false);
                    })?;
                Ok(())
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        if let Some((next_msg, resolver)) = self.connection.next_frame() {
            // FIXME: having the body here is too verbose, impl Display on frame instead: trace!("will write to buffer: {:?}", next_msg);
            trace!("Will write to buffer");
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => {
                    self.serialized_frames.push_back((sz, resolver));
                    Ok(())
                }
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.connection.requeue_frame((next_msg, resolver))?;
                            Ok(())
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            let error = Error::SerialisationError(Arc::new(e));
                            self.connection.set_error(error.clone())?;
                            Err(error)
                        }
                    }
                }
            }
        } else {
            Ok(())
        }
    }

    fn parse(&mut self) -> Result<()> {
        if self.can_parse() {
            if let Some(frame) = self.do_parse()? {
                self.connection.handle_frame(frame)?;
            }
        }
        Ok(())
    }

    fn do_parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.data()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                self.receive_buffer.consume(consumed, false);
                Ok(Some(f))
            }
            Err(e) => {
                if e.is_incomplete() {
                    self.receive_buffer.shift();
                    Ok(None)
                } else {
                    error!("parse error: {:?}", e);
                    let error = Error::ParsingError(e);
                    self.connection.set_error(error.clone())?;
                    Err(error)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use pyo3::prelude::*;

use crate::tables;

#[pyfunction]
pub fn angular_grid(num_points: usize) -> (Vec<(f64, f64, f64)>, Vec<f64>) {
    let offsets = tables::offsets::offsets();

    let offset: usize = match offsets.get(&num_points) {
        Some(v) => *v,
        None => panic!(
            "angular_grid called with unsupported num_points, allowed are: {:?}",
            valid_input_values()
        ),
    };

    (
        tables::coordinates::COORDINATES[offset..(offset + num_points)].to_vec(),
        tables::weights::WEIGHTS[offset..(offset + num_points)].to_vec(),
    )
}

pub fn get_closest_num_angular(n: usize) -> usize {
    for number in valid_input_values() {
        if number >= n {
            return number;
        }
    }
    panic!("input n too high in get_closest_num_angular");
}

fn valid_input_values() -> Vec<usize> {
    let offsets = tables::offsets::offsets();

    let mut valid_numbers = Vec::new();
    for (k, _) in offsets {
        valid_numbers.push(k);
    }
    valid_numbers.sort();

    valid_numbers
}
<commit_msg>advice by clippy<commit_after>use pyo3::prelude::*;

use crate::tables;

#[pyfunction]
pub fn angular_grid(num_points: usize) -> (Vec<(f64, f64, f64)>, Vec<f64>) {
    let offsets = tables::offsets::offsets();

    let offset: usize = match offsets.get(&num_points) {
        Some(v) => *v,
        None => panic!(
            "angular_grid called with unsupported num_points, allowed are: {:?}",
            valid_input_values()
        ),
    };

    (
        tables::coordinates::COORDINATES[offset..(offset + num_points)].to_vec(),
        tables::weights::WEIGHTS[offset..(offset + num_points)].to_vec(),
    )
}

pub fn get_closest_num_angular(n: usize) -> usize {
    for number in valid_input_values() {
        if number >= n {
            return number;
        }
    }
    panic!("input n too high in get_closest_num_angular");
}

fn valid_input_values() -> Vec<usize> {
    let offsets = tables::offsets::offsets();

    let mut valid_numbers = Vec::new();
    for (k, _) in offsets {
        valid_numbers.push(k);
    }
    valid_numbers.sort_unstable();

    valid_numbers
}
<|endoftext|>


<commit_before>// Logging configuration

extern crate log;

struct NormalLogger;
impl log::Log for NormalLogger {
    fn enabled(&self, metadata: &log::LogMetadata) -> bool {
        metadata.level() <= log::LogLevel::Warn
    }

    fn log(&self, record: &log::LogRecord) {
        if self.enabled(record.metadata()) {
            println!("{}", record.args());
        }
    }
}

struct DebugLogger;
impl log::Log for DebugLogger {
    fn enabled(&self, metadata: &log::LogMetadata) -> bool {
        metadata.level() <= log::LogLevel::Trace
    }

    fn log(&self, record: &log::LogRecord) {
        if self.enabled(record.metadata()) {
            println!(
                "{level} ({file}:{line}): {message}",
                level=record.level(),
                file=record.location().file(),
                line=record.location().line(),
                message=record.args()
            );
        }
    }
}

pub fn configure_logging(debug: bool) {
    let result = if debug {
        log::set_logger(
            |max_log_level| {
                max_log_level.set(log::LogLevelFilter::Trace);
                Box::new(DebugLogger)
            }
        )
    } else {
        log::set_logger(
            |max_log_level| {
                max_log_level.set(log::LogLevelFilter::Warn);
                Box::new(NormalLogger)
            }
        )
    };

    if let Err(_) = result {
        unreachable!()
    }
}
<commit_msg>Set normal logging level to error<commit_after>// Logging configuration

extern crate log;

struct NormalLogger;
impl log::Log for NormalLogger {
    fn enabled(&self, metadata: &log::LogMetadata) -> bool {
        metadata.level() <= log::LogLevel::Error
    }

    fn log(&self, record: &log::LogRecord) {
        if self.enabled(record.metadata()) {
            println!("{}", record.args());
        }
    }
}

struct DebugLogger;
impl log::Log for DebugLogger {
    fn enabled(&self, metadata: &log::LogMetadata) -> bool {
        metadata.level() <= log::LogLevel::Trace
    }

    fn log(&self, record: &log::LogRecord) {
        if self.enabled(record.metadata()) {
            println!(
                "{level} ({file}:{line}): {message}",
                level=record.level(),
                file=record.location().file(),
                line=record.location().line(),
                message=record.args()
            );
        }
    }
}

pub fn configure_logging(debug: bool) {
    let result = if debug {
        log::set_logger(
            |max_log_level| {
                max_log_level.set(log::LogLevelFilter::Trace);
                Box::new(DebugLogger)
            }
        )
    } else {
        log::set_logger(
            |max_log_level| {
                max_log_level.set(log::LogLevelFilter::Warn);
                Box::new(NormalLogger)
            }
        )
    };

    if let Err(_) = result {
        unreachable!()
    }
}
<|endoftext|>


<commit_before>/*
 * 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, see
 * <http://www.gnu.org/licenses/>.
 *
 * Sahid Orentino Ferdjaoui <sahid.ferdjaoui@redhat.com>
 */

#![allow(improper_ctypes)]

extern crate libc;

use std::str;

use connect::sys::virConnectPtr;

use connect::Connect;
use error::Error;

pub mod sys {
    #[allow(non_camel_case_types)]
    #[repr(C)]
    pub struct virNetwork {}

    #[allow(non_camel_case_types)]
    pub type virNetworkPtr = *mut virNetwork;
}

#[link(name = "virt")]
extern "C" {
    fn virNetworkLookupByID(c: virConnectPtr, id: libc::c_int) -> sys::virNetworkPtr;
    fn virNetworkLookupByName(c: virConnectPtr, id: *const libc::c_char) -> sys::virNetworkPtr;
    fn virNetworkLookupByUUIDString(c: virConnectPtr,
                                    uuid: *const libc::c_char)
                                    -> sys::virNetworkPtr;
    fn virNetworkCreate(ptr: sys::virNetworkPtr) -> libc::c_int;
    fn virNetworkDefineXML(c: virConnectPtr, xml: *const libc::c_char) -> sys::virNetworkPtr;
    fn virNetworkCreateXML(c: virConnectPtr,
                           xml: *const libc::c_char,
                           flags: libc::c_uint)
                           -> sys::virNetworkPtr;
    fn virNetworkDestroy(ptr: sys::virNetworkPtr) -> libc::c_int;
    fn virNetworkUndefine(ptr: sys::virNetworkPtr) -> libc::c_int;
    fn virNetworkFree(ptr: sys::virNetworkPtr) -> libc::c_int;
    fn virNetworkIsActive(ptr: sys::virNetworkPtr) -> libc::c_int;
    fn virNetworkGetName(ptr: sys::virNetworkPtr) -> *const libc::c_char;
    fn virNetworkGetUUIDString(ptr: sys::virNetworkPtr, uuiptr: *mut libc::c_char) -> libc::c_int;
    fn virNetworkGetXMLDesc(ptr: sys::virNetworkPtr, flags: libc::c_uint) -> *mut libc::c_char;
    fn virNetworkGetBridgeName(ptr: sys::virNetworkPtr) -> *mut libc::c_char;
    fn virNetworkGetAutostart(ptr: sys::virNetworkPtr, autostart: *mut libc::c_int) -> libc::c_int;
    fn virNetworkSetAutostart(ptr: sys::virNetworkPtr, autostart: libc::c_uint) -> libc::c_int;
    fn virNetworkUpdate(ptr: sys::virNetworkPtr,
                        cmptr: libc::c_uint,
                        section: libc::c_uint,
                        index: libc::c_uint,
                        xml: *const libc::c_char,
                        flags: libc::c_uint)
                        -> libc::c_int;
    fn virNetworkGetConnect(ptr: sys::virNetworkPtr) -> virConnectPtr;
}

pub type NetworkXMLFlags = self::libc::c_uint;
pub const VIR_NETWORK_XML_INACTIVE: NetworkXMLFlags = 1 << 0;

pub type NetworkUpdateCommand = self::libc::c_uint;
pub const VIR_NETWORK_UPDATE_COMMAND_NONE: NetworkUpdateCommand = 0;
pub const VIR_NETWORK_UPDATE_COMMAND_MODIFY: NetworkUpdateCommand = 1;
pub const VIR_NETWORK_UPDATE_COMMAND_DELETE: NetworkUpdateCommand = 2;
pub const VIR_NETWORK_UPDATE_COMMAND_ADD_LAST: NetworkUpdateCommand = 3;
pub const VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST: NetworkUpdateCommand = 4;

pub type NetworkUpdateSection = self::libc::c_uint;
pub const VIR_NETWORK_SECTION_NONE: NetworkUpdateSection = 0;
pub const VIR_NETWORK_SECTION_BRIDGE: NetworkUpdateSection = 1;
pub const VIR_NETWORK_SECTION_DOMAIN: NetworkUpdateSection = 2;
pub const VIR_NETWORK_SECTION_IP: NetworkUpdateSection = 3;
pub const VIR_NETWORK_SECTION_IP_DHCP_HOST: NetworkUpdateSection = 4;
pub const VIR_NETWORK_SECTION_IP_DHCP_RANGE: NetworkUpdateSection = 5;
pub const VIR_NETWORK_SECTION_FORWARD: NetworkUpdateSection = 6;
pub const VIR_NETWORK_SECTION_FORWARD_INTERFACE: NetworkUpdateSection = 7;
pub const VIR_NETWORK_SECTION_FORWARD_PF: NetworkUpdateSection = 8;
pub const VIR_NETWORK_SECTION_PORTGROUP: NetworkUpdateSection = 9;
pub const VIR_NETWORK_SECTION_DNS_HOST: NetworkUpdateSection = 10;
pub const VIR_NETWORK_SECTION_DNS_TXT: NetworkUpdateSection = 11;
pub const VIR_NETWORK_SECTION_DNS_SRV: NetworkUpdateSection = 12;

pub type NetworkUpdateFlags = self::libc::c_uint;
pub const VIR_NETWORK_UPDATE_AFFECT_CURRENT: NetworkUpdateFlags = 0;
pub const VIR_NETWORK_UPDATE_AFFECT_LIVE: NetworkUpdateFlags = 1 << 0;
pub const VIR_NETWORK_UPDATE_AFFECT_CONFIG: NetworkUpdateFlags = 1 << 1;

#[derive(Debug)]
pub struct Network {
    ptr: Option<sys::virNetworkPtr>,
}

impl Drop for Network {
    fn drop(&mut self) {
        if self.ptr.is_some() {
            if let Err(e) = self.free() {
                panic!("Unable to drop memory for Network, code {}, message: {}",
                       e.code,
                       e.message)
            }
        }
    }
}

impl Network {
    pub fn new(ptr: sys::virNetworkPtr) -> Network {
        return Network { ptr: Some(ptr) };
    }

    pub fn as_ptr(&self) -> sys::virNetworkPtr {
        self.ptr.unwrap()
    }

    pub fn get_connect(&self) -> Result<Connect, Error> {
        unsafe {
            let ptr = virNetworkGetConnect(self.as_ptr());
            if ptr.is_null() {
                return Err(Error::new());
            }
            return Ok(Connect::new(ptr));
        }
    }

    pub fn lookup_by_id(conn: &Connect, id: u32) -> Result<Network, Error> {
        unsafe {
            let ptr = virNetworkLookupByID(conn.as_ptr(), id as libc::c_int);
            if ptr.is_null() {
                return Err(Error::new());
            }
            return Ok(Network::new(ptr));
        }
    }

    pub fn lookup_by_name(conn: &Connect, id: &str) -> Result<Network, Error> {
        unsafe {
            let ptr = virNetworkLookupByName(conn.as_ptr(), string_to_c_chars!(id));
            if ptr.is_null() {
                return Err(Error::new());
            }
            return Ok(Network::new(ptr));
        }
    }

    pub fn lookup_by_uuid_string(conn: &Connect, uuid: &str) -> Result<Network, Error> {
        unsafe {
            let ptr = virNetworkLookupByUUIDString(conn.as_ptr(), string_to_c_chars!(uuid));
            if ptr.is_null() {
                return Err(Error::new());
            }
            return Ok(Network::new(ptr));
        }
    }

    pub fn get_name(&self) -> Result<String, Error> {
        unsafe {
            let n = virNetworkGetName(self.as_ptr());
            if n.is_null() {
                return Err(Error::new());
            }
            return Ok(c_chars_to_string!(n, nofree));
        }
    }

    pub fn get_uuid_string(&self) -> Result<String, Error> {
        unsafe {
            let mut uuid: [libc::c_char; 37] = [0; 37];
            if virNetworkGetUUIDString(self.as_ptr(), uuid.as_mut_ptr()) == -1 {
                return Err(Error::new());
            }
            return Ok(c_chars_to_string!(uuid.as_ptr(), nofree));
        }
    }

    pub fn get_bridge_name(&self) -> Result<String, Error> {
        unsafe {
            let n = virNetworkGetBridgeName(self.as_ptr());
            if n.is_null() {
                return Err(Error::new());
            }
            return Ok(c_chars_to_string!(n));
        }
    }

    pub fn get_xml_desc(&self, flags: NetworkXMLFlags) -> Result<String, Error> {
        unsafe {
            let xml = virNetworkGetXMLDesc(self.as_ptr(), flags);
            if xml.is_null() {
                return Err(Error::new());
            }
            return Ok(c_chars_to_string!(xml));
        }
    }

    pub fn create(&self) -> Result<u32, Error> {
        unsafe {
            let ret = virNetworkCreate(self.as_ptr());
            if ret == -1 {
                return Err(Error::new());
            }
            return Ok(ret as u32);
        }
    }

    pub fn define_xml(conn: &Connect, xml: &str) -> Result<Network, Error> {
        unsafe {
            let ptr = virNetworkDefineXML(conn.as_ptr(), string_to_c_chars!(xml));
            if ptr.is_null() {
                return Err(Error::new());
            }
            return Ok(Network::new(ptr));
        }
    }

    pub fn create_xml(conn: &Connect, xml: &str, flags: u32) -> Result<Network, Error> {
        unsafe {
            let ptr = virNetworkCreateXML(conn.as_ptr(),
                                          string_to_c_chars!(xml),
                                          flags as libc::c_uint);
            if ptr.is_null() {
                return Err(Error::new());
            }
            return Ok(Network::new(ptr));
        }
    }

    pub fn destroy(&self) -> Result<(), Error> {
        unsafe {
            if virNetworkDestroy(self.as_ptr()) == -1 {
                return Err(Error::new());
            }
            return Ok(());
        }
    }

    pub fn undefine(&self) -> Result<(), Error> {
        unsafe {
            if virNetworkUndefine(self.as_ptr()) == -1 {
                return Err(Error::new());
            }
            return Ok(());
        }
    }

    pub fn free(&mut self) -> Result<(), Error> {
        unsafe {
            if virNetworkFree(self.as_ptr()) == -1 {
                return Err(Error::new());
            }
            self.ptr = None;
            return Ok(());
        }
    }

    pub fn is_active(&self) -> Result<bool, Error> {
        unsafe {
            let ret = virNetworkIsActive(self.as_ptr());
            if ret == -1 {
                return Err(Error::new());
            }
            return Ok(ret == 1);
        }
    }

    pub fn get_autostart(&self) -> Result<bool, Error> {
        unsafe {
            let mut auto = 0;
            let ret = virNetworkGetAutostart(self.as_ptr(), &mut auto);
            if ret == -1 {
                return Err(Error::new());
            }
            return Ok(auto == 1);
        }
    }

    pub fn set_autostart(&self, autostart: bool) -> Result<u32, Error> {
        unsafe {
            let ret = virNetworkSetAutostart(self.as_ptr(), autostart as libc::c_uint);
            if ret == -1 {
                return Err(Error::new());
            }
            return Ok(ret as u32);
        }
    }

    pub fn update(&self,
                  cmd: NetworkUpdateCommand,
                  section: NetworkUpdateSection,
                  index: i32,
                  xml: &str,
                  flags: NetworkUpdateFlags)
                  -> Result<(), Error> {
        unsafe {
            let ret = virNetworkUpdate(self.as_ptr(),
                                       cmd,
                                       section,
                                       index as libc::c_uint,
                                       string_to_c_chars!(xml),
                                       flags);
            if ret == -1 {
                return Err(Error::new());
            }
            return Ok(());
        }
    }
}
<commit_msg>add more suppport for network<commit_after>/*
 * 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, see
 * <http://www.gnu.org/licenses/>.
 *
 * Sahid Orentino Ferdjaoui <sahid.ferdjaoui@redhat.com>
 */

#![allow(improper_ctypes)]

extern crate libc;

use std::str;

use connect::sys::virConnectPtr;

use connect::Connect;
use error::Error;

pub mod sys {
    #[allow(non_camel_case_types)]
    #[repr(C)]
    pub struct virNetwork {}

    #[allow(non_camel_case_types)]
    pub type virNetworkPtr = *mut virNetwork;
}

#[link(name = "virt")]
extern "C" {
    fn virNetworkLookupByID(c: virConnectPtr, id: libc::c_int) -> sys::virNetworkPtr;
    fn virNetworkLookupByName(c: virConnectPtr, id: *const libc::c_char) -> sys::virNetworkPtr;
    fn virNetworkLookupByUUIDString(c: virConnectPtr,
                                    uuid: *const libc::c_char)
                                    -> sys::virNetworkPtr;
    fn virNetworkCreate(ptr: sys::virNetworkPtr) -> libc::c_int;
    fn virNetworkDefineXML(c: virConnectPtr, xml: *const libc::c_char) -> sys::virNetworkPtr;
    fn virNetworkCreateXML(c: virConnectPtr,
                           xml: *const libc::c_char,
                           flags: libc::c_uint)
                           -> sys::virNetworkPtr;
    fn virNetworkDestroy(ptr: sys::virNetworkPtr) -> libc::c_int;
    fn virNetworkUndefine(ptr: sys::virNetworkPtr) -> libc::c_int;
    fn virNetworkFree(ptr: sys::virNetworkPtr) -> libc::c_int;
    fn virNetworkIsActive(ptr: sys::virNetworkPtr) -> libc::c_int;
    fn virNetworkIsPersistent(ptr: sys::virNetworkPtr) -> libc::c_int;
    fn virNetworkGetName(ptr: sys::virNetworkPtr) -> *const libc::c_char;
    fn virNetworkGetUUIDString(ptr: sys::virNetworkPtr, uuiptr: *mut libc::c_char) -> libc::c_int;
    fn virNetworkGetXMLDesc(ptr: sys::virNetworkPtr, flags: libc::c_uint) -> *mut libc::c_char;
    fn virNetworkGetBridgeName(ptr: sys::virNetworkPtr) -> *mut libc::c_char;
    fn virNetworkGetAutostart(ptr: sys::virNetworkPtr, autostart: *mut libc::c_int) -> libc::c_int;
    fn virNetworkSetAutostart(ptr: sys::virNetworkPtr, autostart: libc::c_uint) -> libc::c_int;
    fn virNetworkUpdate(ptr: sys::virNetworkPtr,
                        cmptr: libc::c_uint,
                        section: libc::c_uint,
                        index: libc::c_uint,
                        xml: *const libc::c_char,
                        flags: libc::c_uint)
                        -> libc::c_int;
    fn virNetworkGetConnect(ptr: sys::virNetworkPtr) -> virConnectPtr;
}

pub type NetworkXMLFlags = self::libc::c_uint;
pub const VIR_NETWORK_XML_INACTIVE: NetworkXMLFlags = 1 << 0;

pub type NetworkUpdateCommand = self::libc::c_uint;
pub const VIR_NETWORK_UPDATE_COMMAND_NONE: NetworkUpdateCommand = 0;
pub const VIR_NETWORK_UPDATE_COMMAND_MODIFY: NetworkUpdateCommand = 1;
pub const VIR_NETWORK_UPDATE_COMMAND_DELETE: NetworkUpdateCommand = 2;
pub const VIR_NETWORK_UPDATE_COMMAND_ADD_LAST: NetworkUpdateCommand = 3;
pub const VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST: NetworkUpdateCommand = 4;

pub type NetworkUpdateSection = self::libc::c_uint;
pub const VIR_NETWORK_SECTION_NONE: NetworkUpdateSection = 0;
pub const VIR_NETWORK_SECTION_BRIDGE: NetworkUpdateSection = 1;
pub const VIR_NETWORK_SECTION_DOMAIN: NetworkUpdateSection = 2;
pub const VIR_NETWORK_SECTION_IP: NetworkUpdateSection = 3;
pub const VIR_NETWORK_SECTION_IP_DHCP_HOST: NetworkUpdateSection = 4;
pub const VIR_NETWORK_SECTION_IP_DHCP_RANGE: NetworkUpdateSection = 5;
pub const VIR_NETWORK_SECTION_FORWARD: NetworkUpdateSection = 6;
pub const VIR_NETWORK_SECTION_FORWARD_INTERFACE: NetworkUpdateSection = 7;
pub const VIR_NETWORK_SECTION_FORWARD_PF: NetworkUpdateSection = 8;
pub const VIR_NETWORK_SECTION_PORTGROUP: NetworkUpdateSection = 9;
pub const VIR_NETWORK_SECTION_DNS_HOST: NetworkUpdateSection = 10;
pub const VIR_NETWORK_SECTION_DNS_TXT: NetworkUpdateSection = 11;
pub const VIR_NETWORK_SECTION_DNS_SRV: NetworkUpdateSection = 12;

pub type NetworkUpdateFlags = self::libc::c_uint;
pub const VIR_NETWORK_UPDATE_AFFECT_CURRENT: NetworkUpdateFlags = 0;
pub const VIR_NETWORK_UPDATE_AFFECT_LIVE: NetworkUpdateFlags = 1 << 0;
pub const VIR_NETWORK_UPDATE_AFFECT_CONFIG: NetworkUpdateFlags = 1 << 1;

#[derive(Debug)]
pub struct Network {
    ptr: Option<sys::virNetworkPtr>,
}

impl Drop for Network {
    fn drop(&mut self) {
        if self.ptr.is_some() {
            if let Err(e) = self.free() {
                panic!("Unable to drop memory for Network, code {}, message: {}",
                       e.code,
                       e.message)
            }
        }
    }
}

impl Network {
    pub fn new(ptr: sys::virNetworkPtr) -> Network {
        return Network { ptr: Some(ptr) };
    }

    pub fn as_ptr(&self) -> sys::virNetworkPtr {
        self.ptr.unwrap()
    }

    pub fn get_connect(&self) -> Result<Connect, Error> {
        unsafe {
            let ptr = virNetworkGetConnect(self.as_ptr());
            if ptr.is_null() {
                return Err(Error::new());
            }
            return Ok(Connect::new(ptr));
        }
    }

    pub fn lookup_by_id(conn: &Connect, id: u32) -> Result<Network, Error> {
        unsafe {
            let ptr = virNetworkLookupByID(conn.as_ptr(), id as libc::c_int);
            if ptr.is_null() {
                return Err(Error::new());
            }
            return Ok(Network::new(ptr));
        }
    }

    pub fn lookup_by_name(conn: &Connect, id: &str) -> Result<Network, Error> {
        unsafe {
            let ptr = virNetworkLookupByName(conn.as_ptr(), string_to_c_chars!(id));
            if ptr.is_null() {
                return Err(Error::new());
            }
            return Ok(Network::new(ptr));
        }
    }

    pub fn lookup_by_uuid_string(conn: &Connect, uuid: &str) -> Result<Network, Error> {
        unsafe {
            let ptr = virNetworkLookupByUUIDString(conn.as_ptr(), string_to_c_chars!(uuid));
            if ptr.is_null() {
                return Err(Error::new());
            }
            return Ok(Network::new(ptr));
        }
    }

    pub fn get_name(&self) -> Result<String, Error> {
        unsafe {
            let n = virNetworkGetName(self.as_ptr());
            if n.is_null() {
                return Err(Error::new());
            }
            return Ok(c_chars_to_string!(n, nofree));
        }
    }

    pub fn get_uuid_string(&self) -> Result<String, Error> {
        unsafe {
            let mut uuid: [libc::c_char; 37] = [0; 37];
            if virNetworkGetUUIDString(self.as_ptr(), uuid.as_mut_ptr()) == -1 {
                return Err(Error::new());
            }
            return Ok(c_chars_to_string!(uuid.as_ptr(), nofree));
        }
    }

    pub fn get_bridge_name(&self) -> Result<String, Error> {
        unsafe {
            let n = virNetworkGetBridgeName(self.as_ptr());
            if n.is_null() {
                return Err(Error::new());
            }
            return Ok(c_chars_to_string!(n));
        }
    }

    pub fn get_xml_desc(&self, flags: NetworkXMLFlags) -> Result<String, Error> {
        unsafe {
            let xml = virNetworkGetXMLDesc(self.as_ptr(), flags);
            if xml.is_null() {
                return Err(Error::new());
            }
            return Ok(c_chars_to_string!(xml));
        }
    }

    pub fn create(&self) -> Result<u32, Error> {
        unsafe {
            let ret = virNetworkCreate(self.as_ptr());
            if ret == -1 {
                return Err(Error::new());
            }
            return Ok(ret as u32);
        }
    }

    pub fn define_xml(conn: &Connect, xml: &str) -> Result<Network, Error> {
        unsafe {
            let ptr = virNetworkDefineXML(conn.as_ptr(), string_to_c_chars!(xml));
            if ptr.is_null() {
                return Err(Error::new());
            }
            return Ok(Network::new(ptr));
        }
    }

    pub fn create_xml(conn: &Connect, xml: &str, flags: u32) -> Result<Network, Error> {
        unsafe {
            let ptr = virNetworkCreateXML(conn.as_ptr(),
                                          string_to_c_chars!(xml),
                                          flags as libc::c_uint);
            if ptr.is_null() {
                return Err(Error::new());
            }
            return Ok(Network::new(ptr));
        }
    }

    pub fn destroy(&self) -> Result<(), Error> {
        unsafe {
            if virNetworkDestroy(self.as_ptr()) == -1 {
                return Err(Error::new());
            }
            return Ok(());
        }
    }

    pub fn undefine(&self) -> Result<(), Error> {
        unsafe {
            if virNetworkUndefine(self.as_ptr()) == -1 {
                return Err(Error::new());
            }
            return Ok(());
        }
    }

    pub fn free(&mut self) -> Result<(), Error> {
        unsafe {
            if virNetworkFree(self.as_ptr()) == -1 {
                return Err(Error::new());
            }
            self.ptr = None;
            return Ok(());
        }
    }

    pub fn is_active(&self) -> Result<bool, Error> {
        unsafe {
            let ret = virNetworkIsActive(self.as_ptr());
            if ret == -1 {
                return Err(Error::new());
            }
            return Ok(ret == 1);
        }
    }

    pub fn is_persistent(&self) -> Result<bool, Error> {
        unsafe {
            let ret = virNetworkIsPersistent(self.as_ptr());
            if ret == -1 {
                return Err(Error::new());
            }
            return Ok(ret == 1);
        }
    }

    pub fn get_autostart(&self) -> Result<bool, Error> {
        unsafe {
            let mut auto = 0;
            let ret = virNetworkGetAutostart(self.as_ptr(), &mut auto);
            if ret == -1 {
                return Err(Error::new());
            }
            return Ok(auto == 1);
        }
    }

    pub fn set_autostart(&self, autostart: bool) -> Result<u32, Error> {
        unsafe {
            let ret = virNetworkSetAutostart(self.as_ptr(), autostart as libc::c_uint);
            if ret == -1 {
                return Err(Error::new());
            }
            return Ok(ret as u32);
        }
    }

    pub fn update(&self,
                  cmd: NetworkUpdateCommand,
                  section: NetworkUpdateSection,
                  index: i32,
                  xml: &str,
                  flags: NetworkUpdateFlags)
                  -> Result<(), Error> {
        unsafe {
            let ret = virNetworkUpdate(self.as_ptr(),
                                       cmd,
                                       section,
                                       index as libc::c_uint,
                                       string_to_c_chars!(xml),
                                       flags);
            if ret == -1 {
                return Err(Error::new());
            }
            return Ok(());
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

/// An enum for the package types.
pub enum PackageType {
    /// Stands for binary
    Bin,
    /// Stands for library
    Lib,
    /// Stands for source
    Src,

    // the comments are really obvious, haha
}

/// A struct made for storing the version of the packages.
///
/// The format follows [semver 2.0](http://semver.org/), meaning that:
///
/// - versions with different `major` indicates that they are incompatible.
/// - versions with different `minor` but same `major` are largely compatible.
/// - versions with different `patch` but same `major` and `minor` are
///   compatible.
///
/// The `additional` field is an optional field for the package host to put
/// text such as `alpha` or `stable`, it's not involved in the comparisons.
pub struct Version {
    major: u32,
    minor: u32,
    patch: u32,
    additional: Option<String>,
}

/// A struct for storing package informations, such as its name and version.
pub struct Package {
    name: String,
    hash: u32,
    version: Version,
    package_type: PackageType,
    dependencies: Vec<Package>,
}

impl PartialEq for Version {
    fn eq(&self, other: &Self) -> bool {
        self == other
    }
}

impl Eq for Version {}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Version {
    /// This compares one `Version` with another. It only compares the
    /// three main parts of Version (`major`, `minor`, `patch`) and ignores
    /// `additional` as it is meant to let the package host to put additional
    /// messages such as `alpha`, `beta`.
    ///
    /// This functions compares the two `Version`s *absolutely*, meaning that
    /// it doesn't care about whether the two versions are breaking-changes or
    /// not - it just compares.
    fn cmp(&self, other: &Self) -> Ordering {
        if self.major > other.major { Ordering::Greater } else
        if self.major < other.major { Ordering::Less }
        else {
            if self.minor > other.minor { Ordering::Greater } else
            if self.minor < other.minor { Ordering::Less }
            else {
                if self.patch > other.patch { Ordering::Greater } else
                if self.patch < other.patch { Ordering::Less }
                else { Ordering::Equal }
            }
        }
    }
}

impl Version {
    /// Returns the major version X (X.y.z).
    pub fn major(&self) -> u32 {
        self.major
    }

    /// Returns the minor version Y (x.Y.z).
    pub fn minor(&self) -> u32 {
        self.minor
    }

    /// Returns the patch version Z (x.y.Z).
    pub fn patch(&self) -> u32 {
        self.patch
    }

    /// Returns the additional message added by package host or its developers.
    pub fn additional(&self) -> &Option<String> {
        &self.additional
    }

    /// A helper function for checking whether the two versions contains
    /// breaking changes.
    pub fn is_back_compatible(&self, other: &Self) -> bool {
        self.major == other.major
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name &&
        self.version == other.version
    }
}

impl Package {
    /// Returns the name of the package.
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Returns the version of the package.
    pub fn version(&self) -> &Version {
        &self.version
    }

    /// Returns the hash of the package.
    pub fn hash(&self) -> u32 {
        self.hash
    }

    /// Returns the type of the package.
    pub fn package_type(&self) -> &PackageType {
        &self.package_type
    }
}<commit_msg>Deriving Deserialize for Package<commit_after>use std::cmp::Ordering;

/// An enum for the package types.
#[derive(Deserialize)]
pub enum PackageType {
    /// Stands for binary
    Bin,
    /// Stands for library
    Lib,
    /// Stands for source
    Src,

    // the comments are really obvious, haha
}

/// A struct made for storing the version of the packages.
///
/// The format follows [semver 2.0](http://semver.org/), meaning that:
///
/// - versions with different `major` indicates that they are incompatible.
/// - versions with different `minor` but same `major` are largely compatible.
/// - versions with different `patch` but same `major` and `minor` are
///   compatible.
///
/// The `additional` field is an optional field for the package host to put
/// text such as `alpha` or `stable`, it's not involved in the comparisons.
#[derive(Deserialize)]
pub struct Version {
    major: u32,
    minor: u32,
    patch: u32,
    additional: Option<String>,
}

/// A struct for storing package informations, such as its name and version.
#[derive(Deserialize)]
pub struct Package {
    name: String,
    hash: u32,
    version: Version,
    package_type: PackageType,
    dependencies: Vec<Package>,
}

impl PartialEq for Version {
    fn eq(&self, other: &Self) -> bool {
        self == other
    }
}

impl Eq for Version {}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Version {
    /// This compares one `Version` with another. It only compares the
    /// three main parts of Version (`major`, `minor`, `patch`) and ignores
    /// `additional` as it is meant to let the package host to put additional
    /// messages such as `alpha`, `beta`.
    ///
    /// This functions compares the two `Version`s *absolutely*, meaning that
    /// it doesn't care about whether the two versions are breaking-changes or
    /// not - it just compares.
    fn cmp(&self, other: &Self) -> Ordering {
        if self.major > other.major { Ordering::Greater } else
        if self.major < other.major { Ordering::Less }
        else {
            if self.minor > other.minor { Ordering::Greater } else
            if self.minor < other.minor { Ordering::Less }
            else {
                if self.patch > other.patch { Ordering::Greater } else
                if self.patch < other.patch { Ordering::Less }
                else { Ordering::Equal }
            }
        }
    }
}

impl Version {
    /// Returns the major version X (X.y.z).
    pub fn major(&self) -> u32 {
        self.major
    }

    /// Returns the minor version Y (x.Y.z).
    pub fn minor(&self) -> u32 {
        self.minor
    }

    /// Returns the patch version Z (x.y.Z).
    pub fn patch(&self) -> u32 {
        self.patch
    }

    /// Returns the additional message added by package host or its developers.
    pub fn additional(&self) -> &Option<String> {
        &self.additional
    }

    /// A helper function for checking whether the two versions contains
    /// breaking changes.
    pub fn is_back_compatible(&self, other: &Self) -> bool {
        self.major == other.major
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name &&
        self.version == other.version
    }
}

impl Package {
    /// Returns the name of the package.
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Returns the version of the package.
    pub fn version(&self) -> &Version {
        &self.version
    }

    /// Returns the hash of the package.
    pub fn hash(&self) -> u32 {
        self.hash
    }

    /// Returns the type of the package.
    pub fn package_type(&self) -> &PackageType {
        &self.package_type
    }
}<|endoftext|>


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

#![comment = "Wrapper for libxml2's SAX parser."]
#![crate_id = "github.com/bjz/sax-rs#sax:0.1"]

#![crate_type = "lib"]

#![feature(globs)]

extern crate libc;
extern crate sync;

use libc::{c_char, c_int};
use std::mem;
use std::comm::{Receiver, channel};
use std::str;
use std::io::{File, IoResult};
use std::fmt;

use error::ErrorData;

pub mod error;
pub mod ffi;
mod extfn;

/// Events to be sent by the parser.
#[deriving(PartialEq, Clone)]
pub enum ParseEvent {
    /// The document has begun to be processed.
    StartDocument,
    /// The document processing has finished.
    EndDocument,
    /// An opening tag has was parsed.
    StartElement(String, Attributes),
    /// A closing tag was parsed.
    EndElement(String),
    /// Some characters between tags have been recived.
    Characters(String),
    /// A comment tag was parsed.
    Comment(String),
    /// A `CDATA` block was parsed.
    CdataBlock(String),
}

impl fmt::Show for ParseEvent {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StartDocument => write!(fmt, "START DOCUMENT"),
            EndDocument => write!(fmt, "END DOCUMENT"),
            StartElement(ref name, ref atts) => write!(fmt, "<{}{}>", *name, atts),
            EndElement(ref name) => write!(fmt, "</{}>", *name),
            Characters(ref ch) => write!(fmt, "{}", ch.clone()),
            Comment(ref value) => write!(fmt, "", *value),
            CdataBlock(ref value) => write!(fmt, "<![CDATA[{}]]>", *value),
        }
    }
}

#[deriving(PartialEq, Clone)]
pub struct Attribute {
    name: String,
    value: String,
}

/// A list of attributes
#[deriving(PartialEq, Clone)]
pub struct Attributes(Vec<Attribute>);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut ret = Vec::new();
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            ret.push(
                Attribute {
                    name: str::raw::from_c_str(*ptr).to_string(),
                    value: str::raw::from_c_str(*ptr.offset(1)).to_string(),
                }
            );
            ptr = ptr.offset(2);
        }
        Attributes(ret)
    }

    pub fn find<'a>(&'a self, name: &str) -> Option<&'a str> {
        let Attributes(ref s) = *self;
        s.iter().find(|att| name == att.name.as_slice())
                .map(|att| att.value.as_slice())
    }

    pub fn get<'a>(&'a self, name: &str) -> &'a str {
        self.find(name).expect(format!("Could not find an attribute with the name \"{}\"", name))
    }

    pub fn find_clone(&self, name: &str) -> Option<String> {
        self.find(name).map(|v| v.to_string())
    }

    pub fn get_clone(&self, name: &str) -> String {
        self.get(name).to_string()
    }
}

impl fmt::Show for Attributes {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Attributes(ref s) = *self;
        for att in s.iter() {
            try!(write!(fmt, " {}=\"{}\"", att.name, att.value));
        }
        Ok(())
    }
}

/// Either a parse event wrapped in `Ok` or some Error data wrapped in `Err`.
pub type ParseResult = Result<ParseEvent, ErrorData>;

/// Parses the entire XML string.
///
/// # Returns
///
/// A receiver that recieves parse results.
///
/// # Example
///
/// ~~~rust
/// let parser = sax::parse_str(XML_DATA);
/// for result in parser.iter() {
///     match result {
///         Ok(sax::StartDocument) => (),
///         Ok(sax::EndDocument) => break,
///         Ok(event) => println!("{}", event),
///         Err(err) => println!("{}", err),
///     }
/// }
/// ~~~
#[inline(never)]
pub fn parse_str(src: &str) -> Receiver<ParseResult> {
    // ensure that the xml library is ready for use
    use sync::one::{Once, ONCE_INIT};
    static mut INIT: Once = ONCE_INIT;
    unsafe {
        INIT.doit(|| {
            ffi::xmlInitParser();
            std::rt::at_exit(proc() ffi::xmlCleanupParser());
        })
    }

    let len = src.len() as c_int;
    src.to_c_str().with_ref(|c_str| {
        let (sender, receiver) = channel();
        unsafe {
            ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                       mem::transmute(&sender),
                                       c_str, len);
        }
        receiver
    })
}

pub fn parse_file(path: &Path) -> IoResult<Receiver<ParseResult>> {
    File::open(path).and_then(|mut file| file.read_to_str())
                    .and_then(|contents| Ok(parse_str(contents.as_slice())))
}

#[cfg(test)]
mod tests {
    use super::*;

    fn get_mock_atts() -> Attributes {
        Attributes(Vec::from_slice([
            Attribute { name: box "foo", value: box "0" },
            Attribute { name: box "bar", value: box "1" },
            Attribute { name: box "baz", value: box "2" }
        ]))
    }

    #[test]
    fn test_att_get() {
        let atts = get_mock_atts();
        assert_eq!(atts.get("foo"), "0");
        assert_eq!(atts.get("bar"), "1");
        assert_eq!(atts.get("baz"), "2");
    }

    #[test]
    fn test_att_find() {
        let atts = get_mock_atts();
        assert_eq!(atts.find("foo"), Some("0"));
        assert_eq!(atts.find("bar"), Some("1"));
        assert_eq!(atts.find("baz"), Some("2"));
    }

    #[test]
    fn test() {
        let sax = parse_str(
            "<hello><this />test</hello>"
        );
        loop {
            match sax.recv() {
                Ok(StartDocument) => (),
                Ok(EndDocument) => break,
                Ok(event) => println!("{}", event.to_str()),
                Err(err) => println!("{}", err.to_str()),
            }
        }
    }
}
<commit_msg>Update to latest rust nightly<commit_after>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![comment = "Wrapper for libxml2's SAX parser."]
#![crate_id = "github.com/bjz/sax-rs#sax:0.1"]

#![crate_type = "lib"]

#![feature(globs)]

extern crate libc;
extern crate sync;

use libc::{c_char, c_int};
use std::mem;
use std::comm::{Receiver, channel};
use std::str;
use std::io::{File, IoResult};
use std::fmt;

use error::ErrorData;

pub mod error;
pub mod ffi;
mod extfn;

/// Events to be sent by the parser.
#[deriving(PartialEq, Clone)]
pub enum ParseEvent {
    /// The document has begun to be processed.
    StartDocument,
    /// The document processing has finished.
    EndDocument,
    /// An opening tag has was parsed.
    StartElement(String, Attributes),
    /// A closing tag was parsed.
    EndElement(String),
    /// Some characters between tags have been recived.
    Characters(String),
    /// A comment tag was parsed.
    Comment(String),
    /// A `CDATA` block was parsed.
    CdataBlock(String),
}

impl fmt::Show for ParseEvent {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StartDocument => write!(fmt, "START DOCUMENT"),
            EndDocument => write!(fmt, "END DOCUMENT"),
            StartElement(ref name, ref atts) => write!(fmt, "<{}{}>", *name, atts),
            EndElement(ref name) => write!(fmt, "</{}>", *name),
            Characters(ref ch) => write!(fmt, "{}", ch.clone()),
            Comment(ref value) => write!(fmt, "", *value),
            CdataBlock(ref value) => write!(fmt, "<![CDATA[{}]]>", *value),
        }
    }
}

#[deriving(PartialEq, Clone)]
pub struct Attribute {
    name: String,
    value: String,
}

/// A list of attributes
#[deriving(PartialEq, Clone)]
pub struct Attributes(Vec<Attribute>);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut ret = Vec::new();
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            ret.push(
                Attribute {
                    name: str::raw::from_c_str(*ptr).to_string(),
                    value: str::raw::from_c_str(*ptr.offset(1)).to_string(),
                }
            );
            ptr = ptr.offset(2);
        }
        Attributes(ret)
    }

    pub fn find<'a>(&'a self, name: &str) -> Option<&'a str> {
        let Attributes(ref s) = *self;
        s.iter().find(|att| name == att.name.as_slice())
                .map(|att| att.value.as_slice())
    }

    pub fn get<'a>(&'a self, name: &str) -> &'a str {
        self.find(name).expect(format!("Could not find an attribute with the name \"{}\"", name).as_slice())
    }

    pub fn find_clone(&self, name: &str) -> Option<String> {
        self.find(name).map(|v| v.to_string())
    }

    pub fn get_clone(&self, name: &str) -> String {
        self.get(name).to_string()
    }
}

impl fmt::Show for Attributes {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Attributes(ref s) = *self;
        for att in s.iter() {
            try!(write!(fmt, " {}=\"{}\"", att.name, att.value));
        }
        Ok(())
    }
}

/// Either a parse event wrapped in `Ok` or some Error data wrapped in `Err`.
pub type ParseResult = Result<ParseEvent, ErrorData>;

/// Parses the entire XML string.
///
/// # Returns
///
/// A receiver that recieves parse results.
///
/// # Example
///
/// ~~~rust
/// let parser = sax::parse_str(XML_DATA);
/// for result in parser.iter() {
///     match result {
///         Ok(sax::StartDocument) => (),
///         Ok(sax::EndDocument) => break,
///         Ok(event) => println!("{}", event),
///         Err(err) => println!("{}", err),
///     }
/// }
/// ~~~
#[inline(never)]
pub fn parse_str(src: &str) -> Receiver<ParseResult> {
    // ensure that the xml library is ready for use
    use sync::one::{Once, ONCE_INIT};
    static mut INIT: Once = ONCE_INIT;
    unsafe {
        INIT.doit(|| {
            ffi::xmlInitParser();
            std::rt::at_exit(proc() ffi::xmlCleanupParser());
        })
    }

    let len = src.len() as c_int;
    src.to_c_str().with_ref(|c_str| {
        let (sender, receiver) = channel();
        unsafe {
            ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                       mem::transmute(&sender),
                                       c_str, len);
        }
        receiver
    })
}

pub fn parse_file(path: &Path) -> IoResult<Receiver<ParseResult>> {
    File::open(path).and_then(|mut file| file.read_to_str())
                    .and_then(|contents| Ok(parse_str(contents.as_slice())))
}

#[cfg(test)]
mod tests {
    use super::*;

    fn get_mock_atts() -> Attributes {
        Attributes(Vec::from_slice([
            Attribute { name: box "foo", value: box "0" },
            Attribute { name: box "bar", value: box "1" },
            Attribute { name: box "baz", value: box "2" }
        ]))
    }

    #[test]
    fn test_att_get() {
        let atts = get_mock_atts();
        assert_eq!(atts.get("foo"), "0");
        assert_eq!(atts.get("bar"), "1");
        assert_eq!(atts.get("baz"), "2");
    }

    #[test]
    fn test_att_find() {
        let atts = get_mock_atts();
        assert_eq!(atts.find("foo"), Some("0"));
        assert_eq!(atts.find("bar"), Some("1"));
        assert_eq!(atts.find("baz"), Some("2"));
    }

    #[test]
    fn test() {
        let sax = parse_str(
            "<hello><this />test</hello>"
        );
        loop {
            match sax.recv() {
                Ok(StartDocument) => (),
                Ok(EndDocument) => break,
                Ok(event) => println!("{}", event.to_str()),
                Err(err) => println!("{}", err.to_str()),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::fs::{OpenOptions, File};
use crc::crc32::checksum_ieee;
use byteorder::{BigEndian, ByteOrder};
use std::io::{self, Write, Read};

pub static SEGMENT_FILE_NAME_LEN: usize = 20;
pub static SEGMENT_FILE_NAME_EXTENSION: &'static str = "log";

#[derive(Debug)]
pub enum MessageError {
    IoError(io::Error),
    InvalidCRC,
}

impl From<io::Error> for MessageError {
    fn from(e: io::Error) -> MessageError {
        MessageError::IoError(e)
    }
}

macro_rules! read_n {
    ($reader:expr, $buf:expr, $size:expr, $err_msg:expr) => ({

        match $reader.read(&mut $buf) {
            Ok(s) if s == $size => (),
            Ok(_) => return Err(
                MessageError::IoError(
                    io::Error::new(io::ErrorKind::UnexpectedEof, $err_msg))),
            Err(e) => return Err(MessageError::IoError(e)),
        }
    })
}

/// Messages are appended to the log with the following encoding:
///
/// +-----------+--------------+
/// | Bytes     | Value        |
/// +-----------+--------------+
/// | 0-7       | Offset       |
/// | 8-11      | Payload Size |
/// | 12-15     | CRC32 (IEEE) |
/// | 16+       | Payload      |
/// +-----------+--------------+
#[derive(Debug)]
pub struct Message {
    bytes: Vec<u8>,
}

impl Message {
    pub fn new(payload: &[u8], offset: u64) -> Message {
        let mut bytes = vec![0; 16 + payload.len()];
        BigEndian::write_u64(&mut bytes[0..8], offset);
        BigEndian::write_u32(&mut bytes[8..12], payload.len() as u32);
        BigEndian::write_u32(&mut bytes[12..16], checksum_ieee(payload));
        bytes[16..].copy_from_slice(payload);
        Message { bytes: bytes }
    }

    pub fn read<R>(reader: &mut R) -> Result<Message, MessageError>
        where R: Read
    {
        let mut offset_buf = vec![0; 8];
        read_n!(reader, offset_buf, 8, "Unable to read offset");
        let mut size_buf = vec![0; 4];
        read_n!(reader, size_buf, 4, "Unable to read size");
        let mut crc_buf = vec![0; 4];
        read_n!(reader, crc_buf, 4, "Unable to read CRC");

        let size = BigEndian::read_u32(&size_buf) as usize;
        let crc = BigEndian::read_u32(&crc_buf);

        let mut bytes = vec![0; 16 + size];
        read_n!(reader, bytes[16..], size, "Unable to read message payload");

        let payload_crc = checksum_ieee(&bytes[16..]);
        if payload_crc != crc {
            return Err(MessageError::InvalidCRC);
        }

        bytes[0..8].copy_from_slice(&offset_buf);
        bytes[8..12].copy_from_slice(&size_buf);
        bytes[12..16].copy_from_slice(&crc_buf);

        Ok(Message { bytes: bytes })
    }

    #[inline]
    pub fn bytes(&self) -> &[u8] {
        &self.bytes
    }

    #[inline]
    #[allow(dead_code)]
    pub fn crc(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[12..16])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn size(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[8..12])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn offset(&self) -> u64 {
        BigEndian::read_u64(&self.bytes[0..8])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn payload(&self) -> &[u8] {
        &self.bytes[16..]
    }
}

enum SegmentMode {
    ReadWrite {
        /// current file position for the write
        write_pos: usize,

        /// Next offset of the log
        next_offset: u64,

        /// Maximum number of bytes permitted to be appended to the log
        max_bytes: usize,
    },
    Read,
}

/// A segment is a portion of the commit log. Segments are append-only logs written
/// until the maximum size is reached.
pub struct Segment {
    /// File descriptor
    file: File,

    mode: SegmentMode,

    /// Base offset of the log
    base_offset: u64,
}

#[derive(Debug)]
pub enum SegmentAppendError {
    LogFull,
    IoError(io::Error),
}

impl From<io::Error> for SegmentAppendError {
    #[inline]
    fn from(e: io::Error) -> SegmentAppendError {
        SegmentAppendError::IoError(e)
    }
}

/// Holds the pair of offset written to file position in the segment file.
#[derive(Copy, Clone, Debug)]
pub struct LogEntryMetadata {
    offset: u64,
    file_pos: u32,
}

impl LogEntryMetadata {
    #[inline]
    pub fn offset(&self) -> u64 {
        self.offset
    }

    #[inline]
    pub fn file_pos(&self) -> u32 {
        self.file_pos
    }
}

impl Segment {
    pub fn new<P>(log_dir: P, base_offset: u64, max_bytes: usize) -> io::Result<Segment>
        where P: AsRef<Path>
    {
        let log_path = {
            // the log is of the form BASE_OFFSET.log
            let mut path_buf = PathBuf::new();
            path_buf.push(&log_dir);
            path_buf.push(format!("{:020}", base_offset));
            path_buf.set_extension(SEGMENT_FILE_NAME_EXTENSION);
            path_buf
        };

        let f = try!(OpenOptions::new()
            .write(true)
            .read(true)
            .create_new(true)
            .append(true)
            .open(&log_path));

        Ok(Segment {
            file: f,

            mode: SegmentMode::ReadWrite {
                write_pos: 0,
                next_offset: base_offset,
                max_bytes: max_bytes,
            },

            base_offset: base_offset,
        })
    }

    pub fn open<P>(seg_path: P) -> io::Result<Segment>
        where P: AsRef<Path>
    {
        let seg_file = try!(OpenOptions::new()
            .read(true)
            .write(false)
            .append(false)
            .open(&seg_path));

        let filename = seg_path.as_ref().file_name().unwrap().to_str().unwrap();
        let base_offset = match u64::from_str_radix(&filename[0..SEGMENT_FILE_NAME_LEN], 10) {
            Ok(v) => v,
            Err(_) => {
                return Err(io::Error::new(io::ErrorKind::InvalidData,
                                          "Segment file name does not parse as u64"))
            }
        };

        Ok(Segment {
            file: seg_file,
            mode: SegmentMode::Read,
            base_offset: base_offset,
        })
    }

    // TODO: doesn't make sense
    pub fn next_offset(&self) -> u64 {
        match self.mode {
            SegmentMode::ReadWrite { write_pos, next_offset, max_bytes } => next_offset,
            _ => 0
        }
    }

    #[inline]
    #[allow(dead_code)]
    pub fn starting_offset(&self) -> u64 {
        self.base_offset
    }

    pub fn append(&mut self, payload: &[u8]) -> Result<LogEntryMetadata, SegmentAppendError> {
        let (write_pos, off, max_bytes) = match self.mode {
            SegmentMode::ReadWrite { write_pos, next_offset, max_bytes } =>
                (write_pos, next_offset, max_bytes),
            _ => return Err(SegmentAppendError::LogFull),
        };

        let msg = Message::new(payload, off);
        // ensure we have the capacity
        if msg.bytes().len() + write_pos > max_bytes {
            return Err(SegmentAppendError::LogFull);
        }

        try!(self.file.write_all(msg.bytes()));
        self.mode = SegmentMode::ReadWrite {
            write_pos: write_pos + msg.bytes().len(),
            next_offset: off + 1,
            max_bytes: max_bytes,
        };
        Ok(LogEntryMetadata {
            offset: off,
            file_pos: write_pos as u32,
        })
    }

    // TODO: async flush strategy
    pub fn flush_sync(&mut self) -> io::Result<()> {
        self.file.flush()
    }

    /*pub fn read_at_pos(&mut self, pos: u32) -> Result<Message, MessageError> {

    }*/
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;
    use super::super::testutil::*;
    use std::io;

    #[test]
    fn message_construction() {
        let msg = Message::new(b"123456789", 1234567u64);
        assert_eq!(msg.offset(), 1234567u64);
        assert_eq!(msg.payload(), b"123456789");
        assert_eq!(msg.crc(), 0xcbf43926);
        assert_eq!(msg.size(), 9u32);
    }

    #[test]
    fn message_read() {
        let msg = Message::new(b"123456789", 1234567u64);
        let mut buf_reader = io::BufReader::new(msg.bytes());
        let read_msg_result = Message::read(&mut buf_reader);
        assert!(read_msg_result.is_ok(), "result = {:?}", read_msg_result);

        let read_msg = read_msg_result.unwrap();
        assert_eq!(read_msg.offset(), 1234567u64);
        assert_eq!(read_msg.payload(), b"123456789");
        assert_eq!(read_msg.crc(), 0xcbf43926);
        assert_eq!(read_msg.size(), 9u32);
    }

    #[test]
    fn message_read_invalid_crc() {
        let mut msg =
            Message::new(b"123456789", 1234567u64).bytes().iter().cloned().collect::<Vec<u8>>();
        // mess with the payload such that the CRC does not match
        let last_ind = msg.len() - 1;
        msg[last_ind] += 1u8;

        let mut buf_reader = io::BufReader::new(msg.as_slice());
        let read_msg_result = Message::read(&mut buf_reader);
        let matches_invalid_crc = match read_msg_result {
            Err(MessageError::InvalidCRC) => true,
            _ => false,
        };
        assert!(matches_invalid_crc,
                "Invalid result, not CRC error. Result = {:?}",
                read_msg_result);
    }

    #[test]
    fn message_read_invalid_payload_length() {
        let mut msg =
            Message::new(b"123456789", 1234567u64).bytes().iter().cloned().collect::<Vec<u8>>();
        // pop the last byte
        msg.pop();

        let mut buf_reader = io::BufReader::new(msg.as_slice());
        let read_msg_result = Message::read(&mut buf_reader);
        let matches_invalid_crc = match read_msg_result {
            Err(MessageError::IoError(ref e)) if e.kind() == io::ErrorKind::UnexpectedEof => true,
            _ => false,
        };
        assert!(matches_invalid_crc,
                "Invalid result, not CRC error. Result = {:?}",
                read_msg_result);
    }

    #[test]
    pub fn log() {
        let path = TestDir::new();
        let mut f = Segment::new(path, 0, 1024).unwrap();

        let p0 = f.append(b"12345").unwrap();
        assert_eq!(p0.offset(), 0);
        assert_eq!(p0.file_pos(), 0);

        let p1 = f.append(b"66666").unwrap();
        assert_eq!(p1.offset(), 1);
        assert_eq!(p1.file_pos(), 21);

        f.flush_sync().unwrap();
    }

    #[bench]
    fn bench_segment_append(b: &mut Bencher) {
        let path = TestDir::new();

        let mut seg = Segment::new(path, 100u64, 100 * 1024 * 1024).unwrap();
        let buf = b"01234567891011121314151617181920";

        b.iter(|| {
            seg.append(buf).unwrap();
        });
    }
}
<commit_msg>Adding read at position<commit_after>use std::path::{Path, PathBuf};
use std::fs::{OpenOptions, File};
use crc::crc32::checksum_ieee;
use byteorder::{BigEndian, ByteOrder};
use std::io::{self, Write, Read, Seek, SeekFrom};

pub static SEGMENT_FILE_NAME_LEN: usize = 20;
pub static SEGMENT_FILE_NAME_EXTENSION: &'static str = "log";

#[derive(Debug)]
pub enum MessageError {
    IoError(io::Error),
    InvalidCRC,
}

impl From<io::Error> for MessageError {
    fn from(e: io::Error) -> MessageError {
        MessageError::IoError(e)
    }
}

macro_rules! read_n {
    ($reader:expr, $buf:expr, $size:expr, $err_msg:expr) => ({

        match $reader.read(&mut $buf) {
            Ok(s) if s == $size => (),
            Ok(_) => return Err(
                MessageError::IoError(
                    io::Error::new(io::ErrorKind::UnexpectedEof, $err_msg))),
            Err(e) => return Err(MessageError::IoError(e)),
        }
    })
}

/// Messages are appended to the log with the following encoding:
///
/// +-----------+--------------+
/// | Bytes     | Value        |
/// +-----------+--------------+
/// | 0-7       | Offset       |
/// | 8-11      | Payload Size |
/// | 12-15     | CRC32 (IEEE) |
/// | 16+       | Payload      |
/// +-----------+--------------+
#[derive(Debug)]
pub struct Message {
    bytes: Vec<u8>,
}

impl Message {
    pub fn new(payload: &[u8], offset: u64) -> Message {
        let mut bytes = vec![0; 16 + payload.len()];
        BigEndian::write_u64(&mut bytes[0..8], offset);
        BigEndian::write_u32(&mut bytes[8..12], payload.len() as u32);
        BigEndian::write_u32(&mut bytes[12..16], checksum_ieee(payload));
        bytes[16..].copy_from_slice(payload);
        Message { bytes: bytes }
    }

    pub fn read<R>(reader: &mut R) -> Result<Message, MessageError>
        where R: Read
    {
        let mut offset_buf = vec![0; 8];
        read_n!(reader, offset_buf, 8, "Unable to read offset");
        let mut size_buf = vec![0; 4];
        read_n!(reader, size_buf, 4, "Unable to read size");
        let mut crc_buf = vec![0; 4];
        read_n!(reader, crc_buf, 4, "Unable to read CRC");

        let size = BigEndian::read_u32(&size_buf) as usize;
        let crc = BigEndian::read_u32(&crc_buf);

        let mut bytes = vec![0; 16 + size];
        read_n!(reader, bytes[16..], size, "Unable to read message payload");

        let payload_crc = checksum_ieee(&bytes[16..]);
        if payload_crc != crc {
            return Err(MessageError::InvalidCRC);
        }

        bytes[0..8].copy_from_slice(&offset_buf);
        bytes[8..12].copy_from_slice(&size_buf);
        bytes[12..16].copy_from_slice(&crc_buf);

        Ok(Message { bytes: bytes })
    }

    #[inline]
    pub fn bytes(&self) -> &[u8] {
        &self.bytes
    }

    #[inline]
    #[allow(dead_code)]
    pub fn crc(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[12..16])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn size(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[8..12])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn offset(&self) -> u64 {
        BigEndian::read_u64(&self.bytes[0..8])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn payload(&self) -> &[u8] {
        &self.bytes[16..]
    }
}

enum SegmentMode {
    ReadWrite {
        /// current file position for the write
        write_pos: usize,

        /// Next offset of the log
        next_offset: u64,

        /// Maximum number of bytes permitted to be appended to the log
        max_bytes: usize,
    },
    Read,
}

/// A segment is a portion of the commit log. Segments are append-only logs written
/// until the maximum size is reached.
pub struct Segment {
    /// File descriptor
    file: File,

    mode: SegmentMode,
    has_read: bool,

    /// Base offset of the log
    base_offset: u64,
}

#[derive(Debug)]
pub enum SegmentAppendError {
    LogFull,
    IoError(io::Error),
}

impl From<io::Error> for SegmentAppendError {
    #[inline]
    fn from(e: io::Error) -> SegmentAppendError {
        SegmentAppendError::IoError(e)
    }
}

/// Holds the pair of offset written to file position in the segment file.
#[derive(Copy, Clone, Debug)]
pub struct LogEntryMetadata {
    offset: u64,
    file_pos: u32,
}

impl LogEntryMetadata {
    #[inline]
    pub fn offset(&self) -> u64 {
        self.offset
    }

    #[inline]
    pub fn file_pos(&self) -> u32 {
        self.file_pos
    }
}

impl Segment {
    pub fn new<P>(log_dir: P, base_offset: u64, max_bytes: usize) -> io::Result<Segment>
        where P: AsRef<Path>
    {
        let log_path = {
            // the log is of the form BASE_OFFSET.log
            let mut path_buf = PathBuf::new();
            path_buf.push(&log_dir);
            path_buf.push(format!("{:020}", base_offset));
            path_buf.set_extension(SEGMENT_FILE_NAME_EXTENSION);
            path_buf
        };

        let f = try!(OpenOptions::new()
            .write(true)
            .read(true)
            .create_new(true)
            .append(true)
            .open(&log_path));

        Ok(Segment {
            file: f,

            mode: SegmentMode::ReadWrite {
                write_pos: 0,
                next_offset: base_offset,
                max_bytes: max_bytes,
            },
            has_read: false,

            base_offset: base_offset,
        })
    }

    #[allow(dead_code)]
    pub fn open<P>(seg_path: P) -> io::Result<Segment>
        where P: AsRef<Path>
    {
        let seg_file = try!(OpenOptions::new()
            .read(true)
            .write(false)
            .append(false)
            .open(&seg_path));

        let filename = seg_path.as_ref().file_name().unwrap().to_str().unwrap();
        let base_offset = match u64::from_str_radix(&filename[0..SEGMENT_FILE_NAME_LEN], 10) {
            Ok(v) => v,
            Err(_) => {
                return Err(io::Error::new(io::ErrorKind::InvalidData,
                                          "Segment file name does not parse as u64"))
            }
        };

        Ok(Segment {
            file: seg_file,
            mode: SegmentMode::Read,
            has_read: false,
            base_offset: base_offset,
        })
    }

    // TODO: doesn't make sense
    pub fn next_offset(&self) -> u64 {
        match self.mode {
            SegmentMode::ReadWrite { next_offset, .. } => next_offset,
            _ => 0
        }
    }

    #[inline]
    #[allow(dead_code)]
    pub fn starting_offset(&self) -> u64 {
        self.base_offset
    }

    pub fn append(&mut self, payload: &[u8]) -> Result<LogEntryMetadata, SegmentAppendError> {
        let (write_pos, off, max_bytes) = match self.mode {
            SegmentMode::ReadWrite { write_pos, next_offset, max_bytes } =>
                (write_pos, next_offset, max_bytes),
            _ => return Err(SegmentAppendError::LogFull),
        };

        let msg = Message::new(payload, off);
        // ensure we have the capacity
        if msg.bytes().len() + write_pos > max_bytes {
            return Err(SegmentAppendError::LogFull);
        }

        // move cursor back to write position if we have moved the
        // cursor due to a read
        if self.has_read {
            try!(self.file.seek(SeekFrom::Start(write_pos as u64)));
            self.has_read = false;
        }

        try!(self.file.write_all(msg.bytes()));
        self.mode = SegmentMode::ReadWrite {
            write_pos: write_pos + msg.bytes().len(),
            next_offset: off + 1,
            max_bytes: max_bytes,
        };
        Ok(LogEntryMetadata {
            offset: off,
            file_pos: write_pos as u32,
        })
    }

    // TODO: async flush strategy
    pub fn flush_sync(&mut self) -> io::Result<()> {
        self.file.flush()
    }

    #[allow(dead_code)]
    pub fn read_at_pos(&mut self, file_pos: u32) -> Result<Message, MessageError> {
        self.has_read = true;
        try!(self.file.seek(SeekFrom::Start(file_pos as u64)));
        let msg = try!(Message::read(&mut self.file));
        Ok(msg)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;
    use super::super::testutil::*;
    use std::io;
    use std::path::PathBuf;

    #[test]
    fn message_construction() {
        let msg = Message::new(b"123456789", 1234567u64);
        assert_eq!(msg.offset(), 1234567u64);
        assert_eq!(msg.payload(), b"123456789");
        assert_eq!(msg.crc(), 0xcbf43926);
        assert_eq!(msg.size(), 9u32);
    }

    #[test]
    fn message_read() {
        let msg = Message::new(b"123456789", 1234567u64);
        let mut buf_reader = io::BufReader::new(msg.bytes());
        let read_msg_result = Message::read(&mut buf_reader);
        assert!(read_msg_result.is_ok(), "result = {:?}", read_msg_result);

        let read_msg = read_msg_result.unwrap();
        assert_eq!(read_msg.offset(), 1234567u64);
        assert_eq!(read_msg.payload(), b"123456789");
        assert_eq!(read_msg.crc(), 0xcbf43926);
        assert_eq!(read_msg.size(), 9u32);
    }

    #[test]
    fn message_read_invalid_crc() {
        let mut msg =
            Message::new(b"123456789", 1234567u64).bytes().iter().cloned().collect::<Vec<u8>>();
        // mess with the payload such that the CRC does not match
        let last_ind = msg.len() - 1;
        msg[last_ind] += 1u8;

        let mut buf_reader = io::BufReader::new(msg.as_slice());
        let read_msg_result = Message::read(&mut buf_reader);
        let matches_invalid_crc = match read_msg_result {
            Err(MessageError::InvalidCRC) => true,
            _ => false,
        };
        assert!(matches_invalid_crc,
                "Invalid result, not CRC error. Result = {:?}",
                read_msg_result);
    }

    #[test]
    fn message_read_invalid_payload_length() {
        let mut msg =
            Message::new(b"123456789", 1234567u64).bytes().iter().cloned().collect::<Vec<u8>>();
        // pop the last byte
        msg.pop();

        let mut buf_reader = io::BufReader::new(msg.as_slice());
        let read_msg_result = Message::read(&mut buf_reader);
        let matches_invalid_crc = match read_msg_result {
            Err(MessageError::IoError(ref e)) if e.kind() == io::ErrorKind::UnexpectedEof => true,
            _ => false,
        };
        assert!(matches_invalid_crc,
                "Invalid result, not CRC error. Result = {:?}",
                read_msg_result);
    }

    #[test]
    pub fn log() {
        let path = TestDir::new();
        let mut f = Segment::new(path, 0, 1024).unwrap();

        let p0 = f.append(b"12345").unwrap();
        assert_eq!(p0.offset(), 0);
        assert_eq!(p0.file_pos(), 0);

        let p1 = f.append(b"66666").unwrap();
        assert_eq!(p1.offset(), 1);
        assert_eq!(p1.file_pos(), 21);

        f.flush_sync().unwrap();
    }

    #[test]
    pub fn log_open() {
        let log_dir = TestDir::new();

        {
            let mut f = Segment::new(&log_dir, 0, 1024).unwrap();
            f.append(b"12345").unwrap();
            f.append(b"66666").unwrap();
            f.flush_sync().unwrap();
        }

        // open it
        {
            let mut path_buf = PathBuf::new();
            path_buf.push(&log_dir);
            path_buf.push(format!("{:020}", 0));
            path_buf.set_extension(SEGMENT_FILE_NAME_EXTENSION);

            let res = Segment::open(&path_buf);
            assert!(res.is_ok(), "Err {:?}", res.err());

            let f = res.unwrap();
            assert_eq!(0, f.starting_offset());
        }
    }

    #[test]
    pub fn log_read() {
        let log_dir = TestDir::new();
        let mut f = Segment::new(&log_dir, 0, 1024).unwrap();

        let m0 = f.append(b"0123456789").unwrap();
        let m1 = f.append(b"aaaaaaaaaa").unwrap();
        let m2 = f.append(b"abc").unwrap();

        let m0read = f.read_at_pos(m0.file_pos());
        assert!(m0read.is_ok(), "Err reading message 0: {:?}", m0read.err());
        assert_eq!(b"0123456789", m0read.as_ref().unwrap().payload());
        assert_eq!(0, m0read.as_ref().unwrap().offset());

        let m3 = f.append(b"MIDDLE WRITE").unwrap();

        let m1read = f.read_at_pos(m1.file_pos());
        assert!(m0read.is_ok(), "Err reading message 1: {:?}", m1read.err());
        assert_eq!(b"aaaaaaaaaa", m1read.as_ref().unwrap().payload());
        assert_eq!(1, m1read.as_ref().unwrap().offset());

        let m2read = f.read_at_pos(m2.file_pos());
        assert!(m2read.is_ok(), "Err reading message 2: {:?}", m2read.err());
        assert_eq!(b"abc", m2read.as_ref().unwrap().payload());
        assert_eq!(2, m2read.as_ref().unwrap().offset());

        let m3read = f.read_at_pos(m3.file_pos());
        assert!(m2read.is_ok(), "Err reading message 3: {:?}", m3read.err());
        assert_eq!(b"MIDDLE WRITE", m3read.as_ref().unwrap().payload());
        assert_eq!(3, m3read.as_ref().unwrap().offset());

        let non_exist_res = f.read_at_pos(m3.file_pos() * 2);
        assert!(non_exist_res.is_err());
    }

    #[bench]
    fn bench_segment_append(b: &mut Bencher) {
        let path = TestDir::new();

        let mut seg = Segment::new(path, 100u64, 100 * 1024 * 1024).unwrap();
        let buf = b"01234567891011121314151617181920";

        b.iter(|| {
            seg.append(buf).unwrap();
        });
    }
}
<|endoftext|>