<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::{self, 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) {
        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;
        }
    }

    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(&mut self, error: Error) -> Result<()> {
        for (_, resolver) in std::mem::take(&mut self.serialized_frames) {
            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_error() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionAborted).into())?;
                }
                if event.is_read_closed() || event.is_write_closed() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionReset).into())?;
                }
                // Due to a bug in epoll/mio, it doesn't seem like we can trust this, it's sometimes missing when it should be there
                /*
                if event.is_readable() {
                    self.can_read = true;
                }
                */
                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.socket.flush()?;

        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()?;
            }

            self.socket.flush()?;
        } 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);
                            self.critical_error(Error::SerialisationError(Arc::new(e)))
                        }
                    }
                }
            }
        } 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();
                } else {
                    error!("parse error: {:?}", e);
                    self.critical_error(Error::ParsingError(e))?;
                }
                Ok(None)
            }
        }
    }
}
<commit_msg>IoLoop: unify error path<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::{self, 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) {
        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;
        }
    }

    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.critical_error(err)?;
                        }
                    }
                    Ok(())
                })?,
            waker,
        )
    }

    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_error() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionAborted).into())?;
                }
                if event.is_read_closed() || event.is_write_closed() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionReset).into())?;
                }
                // Due to a bug in epoll/mio, it doesn't seem like we can trust this, it's sometimes missing when it should be there
                /*
                if event.is_readable() {
                    self.can_read = true;
                }
                */
                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())?;
        for (_, resolver) in std::mem::take(&mut self.serialized_frames) {
            if let Some(resolver) = resolver {
                resolver.swear(Err(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.socket.flush()?;

        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()?;
            }

            self.socket.flush()?;
        } 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);
                            self.critical_error(Error::SerialisationError(Arc::new(e)))
                        }
                    }
                }
            }
        } 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();
                } else {
                    error!("parse error: {:?}", e);
                    self.critical_error(Error::ParsingError(e))?;
                }
                Ok(None)
            }
        }
    }
}
<|endoftext|>


<commit_before>mod state;
mod app;
mod renderer;
mod main;
mod start;

pub(crate) use app::TurtleId;
pub use start::start;

use std::sync::Arc;

use glutin::event_loop::EventLoopProxy;
use tokio::io::{self, AsyncBufReadExt};

use crate::ipc_protocol::{ServerConnection, ConnectionError};

use app::App;

/// A custom event used to tell the glutin event loop to redraw the window
#[derive(Debug, Clone, PartialEq, Eq)]
struct RequestRedraw;

/// Manages one or more connections to renderer clients
#[derive(Debug)]
struct RendererServer {
    app: Arc<App>,
    conn: ServerConnection,
    event_loop: EventLoopProxy<RequestRedraw>,
}

impl RendererServer {
    /// Establishes a connection to the client by reading from stdin
    pub async fn new(app: Arc<App>, event_loop: EventLoopProxy<RequestRedraw>) -> Result<Self, ConnectionError> {
        let stdin = io::stdin();
        let mut reader = io::BufReader::new(stdin);

        let mut oneshot_name = String::new();
        reader.read_line(&mut oneshot_name).await?;
        if oneshot_name.is_empty() {
            panic!("bug: unexpected EOF when reading oneshot server name");
        }

        // Remove the trailing newline
        assert_eq!(oneshot_name.pop(), Some('\n'));
        let conn = ServerConnection::connect(oneshot_name)?;

        Ok(Self {app, conn, event_loop})
    }

    /// Serves requests from the client forever
    pub async fn serve(&mut self) -> ! {
        loop {}
    }
}
<commit_msg>Starting to implement server process request handling<commit_after>mod state;
mod app;
mod renderer;
mod main;
mod start;

pub(crate) use app::TurtleId;
pub use start::start;

use std::sync::Arc;

use glutin::event_loop::EventLoopProxy;
use tokio::io::{self, AsyncBufReadExt};

use crate::ipc_protocol::{ServerConnection, ConnectionError, ClientRequest, ServerResponse};

use app::App;

/// A custom event used to tell the glutin event loop to redraw the window
#[derive(Debug, Clone, PartialEq, Eq)]
struct RequestRedraw;

/// Manages one or more connections to renderer clients
#[derive(Debug)]
struct RendererServer {
    app: Arc<App>,
    conn: ServerConnection,
    event_loop: EventLoopProxy<RequestRedraw>,
}

impl RendererServer {
    /// Establishes a connection to the client by reading from stdin
    pub async fn new(app: Arc<App>, event_loop: EventLoopProxy<RequestRedraw>) -> Result<Self, ConnectionError> {
        let stdin = io::stdin();
        let mut reader = io::BufReader::new(stdin);

        let mut oneshot_name = String::new();
        reader.read_line(&mut oneshot_name).await?;
        if oneshot_name.is_empty() {
            panic!("bug: unexpected EOF when reading oneshot server name");
        }

        // Remove the trailing newline
        assert_eq!(oneshot_name.pop(), Some('\n'));
        let conn = ServerConnection::connect(oneshot_name)?;

        Ok(Self {app, conn, event_loop})
    }

    /// Serves requests from the client forever
    pub async fn serve(&mut self) -> ! {
        loop {
            let request = self.conn.recv().await
                .expect("unable to receive request from IPC client");

            use ClientRequest::*;
            match request {
                CreateTurtle => {
                    let id = self.app.add_turtle().await;
                    self.conn.send(ServerResponse::NewTurtle(id))
                        .expect("unable to send IPC response");
                },

                _ => todo!()
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use rocksdb::{DB, Writable, Options, WriteBatch, WriteOptions};
use rocksdb::ffi::DBCFHandle;
use tempdir::TempDir;
use byteorder::{ByteOrder, BigEndian};
use spki_sexp;
use super::Operation;
use time::{Duration, PreciseTime};
use std::thread;
use std::sync::mpsc;
use std::sync::Arc;

pub struct Log {
    dir: TempDir,
    db: Arc<DB>,
    meta: DBCFHandle,
    data: DBCFHandle,
    flush_tx: mpsc::SyncSender<u64>,
}

const META: &'static str = "meta";
const DATA: &'static str = "data";
const META_PREPARED: &'static str = "prepared";
const META_COMMITTED: &'static str = "committed";

impl fmt::Debug for Log {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Log").field("dir", &self.dir.path()).finish()
    }
}

impl Log {
    pub fn new() -> Log {
        let d = TempDir::new("rocksdb-log").expect("new log");
        info!("DB path: {:?}", d.path());
        let mut db = DB::open_default(&d.path().to_string_lossy()).expect("open db");
        let meta = db.create_cf(META, &Options::new()).expect("open meta cf");
        let data = db.create_cf(DATA, &Options::new()).expect("open data cf");
        let db = Arc::new(db);
        let (flush_tx, flush_rx) = mpsc::sync_channel(42);

        let flusher = {
            let db = db.clone();
            thread::Builder::new()
                .name("flusher".to_string())
                .spawn(move || Self::flush_thread_loop(db, flush_rx))
                .expect("spawn flush thread")
        };
        Log {
            dir: d,
            db: db,
            meta: meta,
            data: data,
            flush_tx: flush_tx,
        }
    }

    fn flush_thread_loop(db: Arc<DB>, rx: mpsc::Receiver<u64>) {
        let meta = db.cf_handle(META).expect("open meta cf").clone();
        let data = db.cf_handle(DATA).expect("open data cf").clone();
        loop {
            debug!("Awaiting flush");
            let mut seqno = rx.recv().expect("recive flush seqno");
            loop {
                match rx.try_recv() {
                    Ok(n) => seqno = n,
                    Err(_) => break,
                }
            }
            debug!("Flushing: {:?}", seqno);
            Self::do_commit_to(db.clone(), meta, data, seqno)
        }
    }

    fn tokey(seq: u64) -> [u8; 8] {
        let mut buf: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
        BigEndian::write_u64(&mut buf, seq);
        buf
    }

    fn fromkey(key: &[u8]) -> u64 {
        BigEndian::read_u64(&key)
    }

    pub fn seqno(&self) -> u64 {
        let current = self.read_seqno(META_PREPARED);
        let next = current + 1;
        next
    }

    fn read_seqno(&self, name: &str) -> u64 {
        match self.db.get_cf(self.meta, name.as_bytes()) {
            Ok(Some(val)) => Self::fromkey(&val),
            Ok(None) => 0,
            Err(e) => panic!("Unexpected error getting commit point: {:?}", e),
        }
    }

    pub fn read(&self, seqno: u64) -> Option<Operation> {
        let key = Self::tokey(seqno);
        let ret = match self.db.get_cf(self.data, &key.as_ref()) {
            Ok(Some(val)) => Some(spki_sexp::from_bytes(&val).expect("decode operation")),
            Ok(None) => None,
            Err(e) => panic!("Unexpected error reading index: {:?}: {:?}", seqno, e),
        };
        debug!("Read: {:?} => {:?}", seqno, ret);
        ret
    }

    pub fn verify_sequential(&self, seqno: u64) -> bool {
        let current = self.seqno();
        if !(seqno == 0 || current <= seqno) {
            warn!("Hole in history: saw {}; have: {:?}", seqno, current);
            false
        } else {
            true
        }
    }

    pub fn prepare(&mut self, seqno: u64, op: &Operation) {
        let data_bytes = spki_sexp::as_bytes(op).expect("encode operation");
        debug!("Prepare {:?}", seqno);
        let key = Self::tokey(seqno);
        // match self.db.get_cf(self.data, &key.as_ref()) {
        // Ok(None) => (),
        // Err(e) => panic!("Unexpected error reading index: {:?}: {:?}", seqno, e),
        // Ok(_) => panic!("Unexpected entry at seqno: {:?}", seqno),
        // };

        let t0 = PreciseTime::now();
        let mut batch = WriteBatch::new();
        batch.put_cf(self.data, &key.as_ref(), &data_bytes).expect("Persist operation");
        batch.put_cf(self.meta, META_PREPARED.as_bytes(), &key.as_ref())
             .expect("Persist prepare point");
        self.db.write(batch).expect("Write batch");
        let t1 = PreciseTime::now();
        debug!("Prepare: {}", t0.to(t1));
        trace!("Watermarks: prepared: {:?}; committed: {:?}",
               self.read_seqno(META_PREPARED),
               self.read_seqno(META_COMMITTED));
    }

    pub fn commit_to(&mut self, seqno: u64) {
        debug!("Request commit upto: {:?}", seqno);
        self.flush_tx.send(seqno).expect("Send to flusher")
    }

    fn do_commit_to(db: Arc<DB>, meta: DBCFHandle, data: DBCFHandle, commit_seqno: u64) {
        debug!("Commit {:?}", commit_seqno);
        let key = Self::tokey(commit_seqno);

        let prepared = match db.get_cf(meta, META_PREPARED.as_bytes()) {
            Ok(Some(val)) => Self::fromkey(&val),
            Ok(None) => panic!("Committing {:?} without having prepared?", commit_seqno),
            Err(e) => {
                panic!("Unexpected error reading index: {:?}: {:?}",
                       commit_seqno,
                       e)
            }
        };
        let committed = match db.get_cf(meta, META_COMMITTED.as_bytes()) {
            Ok(Some(val)) => Self::fromkey(&val),
            Ok(None) => 0,
            Err(e) => {
                panic!("Unexpected error reading index: {:?}: {:?}",
                       commit_seqno,
                       e)
            }
        };
        debug!("Committing: {:?}, committed, {:?}, prepared: {:?}",
               committed,
               committed,
               prepared);
        assert!(prepared >= commit_seqno);

        if committed == commit_seqno {
            debug!("Skipping, commits up to date");
            return;
        }

        let t0 = PreciseTime::now();
        let mut opts = WriteOptions::new();
        opts.set_sync(true);
        db.put_cf_opt(meta, META_COMMITTED.as_bytes(), &key.as_ref(), &opts)
          .expect("Persist commit point");
        let t1 = PreciseTime::now();
        debug!("Committed {:?} in: {}", commit_seqno - committed, t0.to(t1));
    }

    pub fn flush(&mut self) -> bool {
        let prepared = self.read_seqno(META_PREPARED);
        let committed = self.read_seqno(META_COMMITTED);
        if committed < prepared {
            info!("Flushing {} ({:?}->{:?})",
                  prepared - committed,
                  committed,
                  prepared);
            self.commit_to(prepared);
            true
        } else {
            false
        }
    }
}
<commit_msg>Refactorage.<commit_after>use std::fmt;
use rocksdb::{DB, Writable, Options, WriteBatch, WriteOptions};
use rocksdb::ffi::DBCFHandle;
use tempdir::TempDir;
use byteorder::{ByteOrder, BigEndian};
use spki_sexp;
use super::Operation;
use time::{Duration, PreciseTime};
use std::thread;
use std::sync::mpsc;
use std::sync::Arc;

pub struct Log {
    dir: TempDir,
    db: Arc<DB>,
    meta: DBCFHandle,
    data: DBCFHandle,
    flush_tx: mpsc::SyncSender<u64>,
}

const META: &'static str = "meta";
const DATA: &'static str = "data";
const META_PREPARED: &'static str = "prepared";
const META_COMMITTED: &'static str = "committed";

impl fmt::Debug for Log {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Log").field("dir", &self.dir.path()).finish()
    }
}

impl Log {
    pub fn new() -> Log {
        let d = TempDir::new("rocksdb-log").expect("new log");
        info!("DB path: {:?}", d.path());
        let mut db = DB::open_default(&d.path().to_string_lossy()).expect("open db");
        let meta = db.create_cf(META, &Options::new()).expect("open meta cf");
        let data = db.create_cf(DATA, &Options::new()).expect("open data cf");
        let db = Arc::new(db);
        let (flush_tx, flush_rx) = mpsc::sync_channel(42);

        let flusher = {
            let db = db.clone();
            thread::Builder::new()
                .name("flusher".to_string())
                .spawn(move || Self::flush_thread_loop(db, flush_rx))
                .expect("spawn flush thread")
        };
        Log {
            dir: d,
            db: db,
            meta: meta,
            data: data,
            flush_tx: flush_tx,
        }
    }

    fn flush_thread_loop(db: Arc<DB>, rx: mpsc::Receiver<u64>) {
        let meta = db.cf_handle(META).expect("open meta cf").clone();
        let data = db.cf_handle(DATA).expect("open data cf").clone();
        loop {
            debug!("Awaiting flush");
            let mut seqno = rx.recv().expect("recive flush seqno");
            loop {
                match rx.try_recv() {
                    Ok(n) => seqno = n,
                    Err(_) => break,
                }
            }
            debug!("Flushing: {:?}", seqno);
            Self::do_commit_to(db.clone(), meta, data, seqno)
        }
    }

    fn tokey(seq: u64) -> [u8; 8] {
        let mut buf: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
        BigEndian::write_u64(&mut buf, seq);
        buf
    }

    fn fromkey(key: &[u8]) -> u64 {
        BigEndian::read_u64(&key)
    }

    pub fn seqno(&self) -> u64 {
        let current = self.read_seqno(META_PREPARED);
        let next = current + 1;
        next
    }

    fn do_read_seqno(db: &DB, meta: DBCFHandle, name: &str) -> u64 {
        match db.get_cf(meta, name.as_bytes()) {
            Ok(Some(val)) => Self::fromkey(&val),
            Ok(None) => 0,
            Err(e) => panic!("Unexpected error getting commit point: {:?}", e),
        }
    }

    fn read_seqno(&self, name: &str) -> u64 {
        Self::do_read_seqno(&self.db, self.meta, name)
    }

    pub fn read(&self, seqno: u64) -> Option<Operation> {
        let key = Self::tokey(seqno);
        let ret = match self.db.get_cf(self.data, &key.as_ref()) {
            Ok(Some(val)) => Some(spki_sexp::from_bytes(&val).expect("decode operation")),
            Ok(None) => None,
            Err(e) => panic!("Unexpected error reading index: {:?}: {:?}", seqno, e),
        };
        debug!("Read: {:?} => {:?}", seqno, ret);
        ret
    }

    pub fn verify_sequential(&self, seqno: u64) -> bool {
        let current = self.seqno();
        if !(seqno == 0 || current <= seqno) {
            warn!("Hole in history: saw {}; have: {:?}", seqno, current);
            false
        } else {
            true
        }
    }

    pub fn prepare(&mut self, seqno: u64, op: &Operation) {
        let data_bytes = spki_sexp::as_bytes(op).expect("encode operation");
        debug!("Prepare {:?}", seqno);
        let key = Self::tokey(seqno);
        // match self.db.get_cf(self.data, &key.as_ref()) {
        // Ok(None) => (),
        // Err(e) => panic!("Unexpected error reading index: {:?}: {:?}", seqno, e),
        // Ok(_) => panic!("Unexpected entry at seqno: {:?}", seqno),
        // };

        let t0 = PreciseTime::now();
        let mut batch = WriteBatch::new();
        batch.put_cf(self.data, &key.as_ref(), &data_bytes).expect("Persist operation");
        batch.put_cf(self.meta, META_PREPARED.as_bytes(), &key.as_ref())
             .expect("Persist prepare point");
        self.db.write(batch).expect("Write batch");
        let t1 = PreciseTime::now();
        debug!("Prepare: {}", t0.to(t1));
        trace!("Watermarks: prepared: {:?}; committed: {:?}",
               self.read_seqno(META_PREPARED),
               self.read_seqno(META_COMMITTED));
    }

    pub fn commit_to(&mut self, seqno: u64) {
        debug!("Request commit upto: {:?}", seqno);
        self.flush_tx.send(seqno).expect("Send to flusher")
    }

    fn do_commit_to(db: Arc<DB>, meta: DBCFHandle, data: DBCFHandle, commit_seqno: u64) {
        debug!("Commit {:?}", commit_seqno);
        let key = Self::tokey(commit_seqno);

        let prepared = Self::do_read_seqno(&db, meta, META_PREPARED);
        let committed = Self::do_read_seqno(&db, meta, META_COMMITTED);

        debug!("Committing: {:?}, committed, {:?}, prepared: {:?}",
               committed,
               committed,
               prepared);
        assert!(prepared >= commit_seqno);

        if committed == commit_seqno {
            debug!("Skipping, commits up to date");
            return;
        }

        let t0 = PreciseTime::now();
        let mut opts = WriteOptions::new();
        opts.set_sync(true);
        db.put_cf_opt(meta, META_COMMITTED.as_bytes(), &key.as_ref(), &opts)
          .expect("Persist commit point");
        let t1 = PreciseTime::now();
        debug!("Committed {:?} in: {}", commit_seqno - committed, t0.to(t1));
    }

    pub fn flush(&mut self) -> bool {
        let prepared = self.read_seqno(META_PREPARED);
        let committed = self.read_seqno(META_COMMITTED);
        if committed < prepared {
            info!("Flushing {} ({:?}->{:?})",
                  prepared - committed,
                  committed,
                  prepared);
            self.commit_to(prepared);
            true
        } else {
            false
        }
    }
}
<|endoftext|>


<commit_before>//! Matrix room version identifiers.

use std::{
    borrow::Cow,
    convert::TryFrom,
    fmt::{self, Display, Formatter},
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use crate::error::Error;

/// Room version identifiers cannot be more than 32 code points.
const MAX_CODE_POINTS: usize = 32;

/// A Matrix room version ID.
///
/// A `RoomVersionId` can be or converted or deserialized from a string slice, and can be converted
/// or serialized back into a string as needed.
///
/// ```
/// # use std::convert::TryFrom;
/// # use ruma_identifiers::RoomVersionId;
/// assert_eq!(RoomVersionId::try_from("1").unwrap().as_ref(), "1");
/// ```
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct RoomVersionId(InnerRoomVersionId);

/// Possibile values for room version, distinguishing between official Matrix versions and custom
/// versions.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum InnerRoomVersionId {
    /// A version 1 room.
    Version1,

    /// A version 2 room.
    Version2,

    /// A version 3 room.
    Version3,

    /// A version 4 room.
    Version4,

    /// A version 5 room.
    Version5,

    /// A version 6 room.
    Version6,

    /// A custom room version.
    Custom(Box<str>),
}

impl RoomVersionId {
    /// Creates a version 1 room ID.
    pub fn version_1() -> Self {
        Self(InnerRoomVersionId::Version1)
    }

    /// Creates a version 2 room ID.
    pub fn version_2() -> Self {
        Self(InnerRoomVersionId::Version2)
    }

    /// Creates a version 3 room ID.
    pub fn version_3() -> Self {
        Self(InnerRoomVersionId::Version3)
    }

    /// Creates a version 4 room ID.
    pub fn version_4() -> Self {
        Self(InnerRoomVersionId::Version4)
    }

    /// Creates a version 5 room ID.
    pub fn version_5() -> Self {
        Self(InnerRoomVersionId::Version5)
    }

    /// Creates a version 6 room ID.
    pub fn version_6() -> Self {
        Self(InnerRoomVersionId::Version6)
    }

    /// Creates a custom room version ID from the given string slice.
    pub fn custom(id: String) -> Self {
        Self(InnerRoomVersionId::Custom(id.into()))
    }

    /// Whether or not this room version is an official one specified by the Matrix protocol.
    pub fn is_official(&self) -> bool {
        !self.is_custom()
    }

    /// Whether or not this is a custom room version.
    pub fn is_custom(&self) -> bool {
        match self.0 {
            InnerRoomVersionId::Custom(_) => true,
            _ => false,
        }
    }

    /// Whether or not this is a version 1 room.
    pub fn is_version_1(&self) -> bool {
        self.0 == InnerRoomVersionId::Version1
    }

    /// Whether or not this is a version 2 room.
    pub fn is_version_2(&self) -> bool {
        self.0 == InnerRoomVersionId::Version2
    }

    /// Whether or not this is a version 3 room.
    pub fn is_version_3(&self) -> bool {
        self.0 == InnerRoomVersionId::Version3
    }

    /// Whether or not this is a version 4 room.
    pub fn is_version_4(&self) -> bool {
        self.0 == InnerRoomVersionId::Version4
    }

    /// Whether or not this is a version 5 room.
    pub fn is_version_5(&self) -> bool {
        self.0 == InnerRoomVersionId::Version5
    }

    /// Whether or not this is a version 6 room.
    pub fn is_version_6(&self) -> bool {
        self.0 == InnerRoomVersionId::Version5
    }
}

impl From<RoomVersionId> for String {
    fn from(id: RoomVersionId) -> Self {
        match id.0 {
            InnerRoomVersionId::Version1 => "1".to_owned(),
            InnerRoomVersionId::Version2 => "2".to_owned(),
            InnerRoomVersionId::Version3 => "3".to_owned(),
            InnerRoomVersionId::Version4 => "4".to_owned(),
            InnerRoomVersionId::Version5 => "5".to_owned(),
            InnerRoomVersionId::Version6 => "6".to_owned(),
            InnerRoomVersionId::Custom(version) => version.into(),
        }
    }
}

impl AsRef<str> for RoomVersionId {
    fn as_ref(&self) -> &str {
        match &self.0 {
            InnerRoomVersionId::Version1 => "1",
            InnerRoomVersionId::Version2 => "2",
            InnerRoomVersionId::Version3 => "3",
            InnerRoomVersionId::Version4 => "4",
            InnerRoomVersionId::Version5 => "5",
            InnerRoomVersionId::Version6 => "6",
            InnerRoomVersionId::Custom(version) => version,
        }
    }
}

impl Display for RoomVersionId {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_ref())
    }
}

#[cfg(feature = "serde")]
impl Serialize for RoomVersionId {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.as_ref())
    }
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for RoomVersionId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        crate::deserialize_id(deserializer, "a Matrix room version ID as a string")
    }
}

impl TryFrom<Cow<'_, str>> for RoomVersionId {
    type Error = Error;

    /// Attempts to create a new Matrix room version ID from a string representation.
    fn try_from(room_version_id: Cow<'_, str>) -> Result<Self, Error> {
        let version = match &room_version_id as &str {
            "1" => Self(InnerRoomVersionId::Version1),
            "2" => Self(InnerRoomVersionId::Version2),
            "3" => Self(InnerRoomVersionId::Version3),
            "4" => Self(InnerRoomVersionId::Version4),
            "5" => Self(InnerRoomVersionId::Version5),
            custom => {
                if custom.is_empty() {
                    return Err(Error::MinimumLengthNotSatisfied);
                } else if custom.chars().count() > MAX_CODE_POINTS {
                    return Err(Error::MaximumLengthExceeded);
                } else {
                    Self(InnerRoomVersionId::Custom(
                        room_version_id.into_owned().into(),
                    ))
                }
            }
        };

        Ok(version)
    }
}

impl TryFrom<&str> for RoomVersionId {
    type Error = crate::error::Error;

    fn try_from(s: &str) -> Result<Self, Self::Error> {
        Self::try_from(Cow::Borrowed(s))
    }
}

impl TryFrom<String> for RoomVersionId {
    type Error = crate::error::Error;

    fn try_from(s: String) -> Result<Self, Self::Error> {
        Self::try_from(Cow::Owned(s))
    }
}

impl PartialEq<&str> for RoomVersionId {
    fn eq(&self, other: &&str) -> bool {
        self.as_ref() == *other
    }
}

impl PartialEq<RoomVersionId> for &str {
    fn eq(&self, other: &RoomVersionId) -> bool {
        *self == other.as_ref()
    }
}

impl PartialEq<String> for RoomVersionId {
    fn eq(&self, other: &String) -> bool {
        self.as_ref() == other
    }
}

impl PartialEq<RoomVersionId> for String {
    fn eq(&self, other: &RoomVersionId) -> bool {
        self == other.as_ref()
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryFrom;

    #[cfg(feature = "serde")]
    use serde_json::{from_str, to_string};

    use super::RoomVersionId;
    use crate::error::Error;

    #[test]
    fn valid_version_1_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("1")
                .expect("Failed to create RoomVersionId.")
                .as_ref(),
            "1"
        );
    }

    #[test]
    fn valid_version_2_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("2")
                .expect("Failed to create RoomVersionId.")
                .as_ref(),
            "2"
        );
    }

    #[test]
    fn valid_version_3_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("3")
                .expect("Failed to create RoomVersionId.")
                .as_ref(),
            "3"
        );
    }

    #[test]
    fn valid_version_4_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("4")
                .expect("Failed to create RoomVersionId.")
                .as_ref(),
            "4"
        );
    }

    #[test]
    fn valid_version_5_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("5")
                .expect("Failed to create RoomVersionId.")
                .as_ref(),
            "5"
        );
    }

    #[test]
    fn valid_custom_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("io.ruma.1")
                .expect("Failed to create RoomVersionId.")
                .as_ref(),
            "io.ruma.1"
        );
    }

    #[test]
    fn empty_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from(""),
            Err(Error::MinimumLengthNotSatisfied)
        );
    }

    #[test]
    fn over_max_code_point_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("0123456789012345678901234567890123456789"),
            Err(Error::MaximumLengthExceeded)
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn serialize_official_room_id() {
        assert_eq!(
            to_string(&RoomVersionId::try_from("1").expect("Failed to create RoomVersionId."))
                .expect("Failed to convert RoomVersionId to JSON."),
            r#""1""#
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn deserialize_official_room_id() {
        let deserialized =
            from_str::<RoomVersionId>(r#""1""#).expect("Failed to convert RoomVersionId to JSON.");

        assert!(deserialized.is_version_1());
        assert!(deserialized.is_official());

        assert_eq!(
            deserialized,
            RoomVersionId::try_from("1").expect("Failed to create RoomVersionId.")
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn serialize_custom_room_id() {
        assert_eq!(
            to_string(
                &RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.")
            )
            .expect("Failed to convert RoomVersionId to JSON."),
            r#""io.ruma.1""#
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn deserialize_custom_room_id() {
        let deserialized = from_str::<RoomVersionId>(r#""io.ruma.1""#)
            .expect("Failed to convert RoomVersionId to JSON.");

        assert!(deserialized.is_custom());

        assert_eq!(
            deserialized,
            RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.")
        );
    }

    #[test]
    fn constructors() {
        assert!(RoomVersionId::version_1().is_version_1());
        assert!(RoomVersionId::version_2().is_version_2());
        assert!(RoomVersionId::version_3().is_version_3());
        assert!(RoomVersionId::version_4().is_version_4());
        assert!(RoomVersionId::version_5().is_version_5());
        assert!(RoomVersionId::custom("foo".into()).is_custom());
    }

    #[test]
    #[allow(clippy::cognitive_complexity)]
    fn predicate_methods() {
        let version_1 = RoomVersionId::try_from("1").expect("Failed to create RoomVersionId.");
        let version_2 = RoomVersionId::try_from("2").expect("Failed to create RoomVersionId.");
        let version_3 = RoomVersionId::try_from("3").expect("Failed to create RoomVersionId.");
        let version_4 = RoomVersionId::try_from("4").expect("Failed to create RoomVersionId.");
        let version_5 = RoomVersionId::try_from("5").expect("Failed to create RoomVersionId.");
        let custom = RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.");

        assert!(version_1.is_version_1());
        assert!(version_2.is_version_2());
        assert!(version_3.is_version_3());
        assert!(version_4.is_version_4());
        assert!(version_5.is_version_5());

        assert!(!version_1.is_version_2());
        assert!(!version_1.is_version_3());
        assert!(!version_1.is_version_4());
        assert!(!version_1.is_version_5());

        assert!(version_1.is_official());
        assert!(version_2.is_official());
        assert!(version_3.is_official());
        assert!(version_4.is_official());
        assert!(version_5.is_official());

        assert!(!version_1.is_custom());
        assert!(!version_2.is_custom());
        assert!(!version_3.is_custom());
        assert!(!version_4.is_custom());
        assert!(!version_5.is_custom());

        assert!(custom.is_custom());
        assert!(!custom.is_official());
        assert!(!custom.is_version_1());
        assert!(!custom.is_version_2());
        assert!(!custom.is_version_3());
        assert!(!custom.is_version_4());
        assert!(!custom.is_version_5());
    }
}
<commit_msg>Fixup for 7b30c2b<commit_after>//! Matrix room version identifiers.

use std::{
    convert::TryFrom,
    fmt::{self, Display, Formatter},
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use crate::error::Error;

/// Room version identifiers cannot be more than 32 code points.
const MAX_CODE_POINTS: usize = 32;

/// A Matrix room version ID.
///
/// A `RoomVersionId` can be or converted or deserialized from a string slice, and can be converted
/// or serialized back into a string as needed.
///
/// ```
/// # use std::convert::TryFrom;
/// # use ruma_identifiers::RoomVersionId;
/// assert_eq!(RoomVersionId::try_from("1").unwrap().as_ref(), "1");
/// ```
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct RoomVersionId(InnerRoomVersionId);

/// Possibile values for room version, distinguishing between official Matrix versions and custom
/// versions.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum InnerRoomVersionId {
    /// A version 1 room.
    Version1,

    /// A version 2 room.
    Version2,

    /// A version 3 room.
    Version3,

    /// A version 4 room.
    Version4,

    /// A version 5 room.
    Version5,

    /// A version 6 room.
    Version6,

    /// A custom room version.
    Custom(Box<str>),
}

impl RoomVersionId {
    /// Creates a version 1 room ID.
    pub fn version_1() -> Self {
        Self(InnerRoomVersionId::Version1)
    }

    /// Creates a version 2 room ID.
    pub fn version_2() -> Self {
        Self(InnerRoomVersionId::Version2)
    }

    /// Creates a version 3 room ID.
    pub fn version_3() -> Self {
        Self(InnerRoomVersionId::Version3)
    }

    /// Creates a version 4 room ID.
    pub fn version_4() -> Self {
        Self(InnerRoomVersionId::Version4)
    }

    /// Creates a version 5 room ID.
    pub fn version_5() -> Self {
        Self(InnerRoomVersionId::Version5)
    }

    /// Creates a version 6 room ID.
    pub fn version_6() -> Self {
        Self(InnerRoomVersionId::Version6)
    }

    /// Creates a custom room version ID from the given string slice.
    pub fn custom(id: String) -> Self {
        Self(InnerRoomVersionId::Custom(id.into()))
    }

    /// Whether or not this room version is an official one specified by the Matrix protocol.
    pub fn is_official(&self) -> bool {
        !self.is_custom()
    }

    /// Whether or not this is a custom room version.
    pub fn is_custom(&self) -> bool {
        match self.0 {
            InnerRoomVersionId::Custom(_) => true,
            _ => false,
        }
    }

    /// Whether or not this is a version 1 room.
    pub fn is_version_1(&self) -> bool {
        self.0 == InnerRoomVersionId::Version1
    }

    /// Whether or not this is a version 2 room.
    pub fn is_version_2(&self) -> bool {
        self.0 == InnerRoomVersionId::Version2
    }

    /// Whether or not this is a version 3 room.
    pub fn is_version_3(&self) -> bool {
        self.0 == InnerRoomVersionId::Version3
    }

    /// Whether or not this is a version 4 room.
    pub fn is_version_4(&self) -> bool {
        self.0 == InnerRoomVersionId::Version4
    }

    /// Whether or not this is a version 5 room.
    pub fn is_version_5(&self) -> bool {
        self.0 == InnerRoomVersionId::Version5
    }

    /// Whether or not this is a version 6 room.
    pub fn is_version_6(&self) -> bool {
        self.0 == InnerRoomVersionId::Version5
    }
}

impl From<RoomVersionId> for String {
    fn from(id: RoomVersionId) -> Self {
        match id.0 {
            InnerRoomVersionId::Version1 => "1".to_owned(),
            InnerRoomVersionId::Version2 => "2".to_owned(),
            InnerRoomVersionId::Version3 => "3".to_owned(),
            InnerRoomVersionId::Version4 => "4".to_owned(),
            InnerRoomVersionId::Version5 => "5".to_owned(),
            InnerRoomVersionId::Version6 => "6".to_owned(),
            InnerRoomVersionId::Custom(version) => version.into(),
        }
    }
}

impl AsRef<str> for RoomVersionId {
    fn as_ref(&self) -> &str {
        match &self.0 {
            InnerRoomVersionId::Version1 => "1",
            InnerRoomVersionId::Version2 => "2",
            InnerRoomVersionId::Version3 => "3",
            InnerRoomVersionId::Version4 => "4",
            InnerRoomVersionId::Version5 => "5",
            InnerRoomVersionId::Version6 => "6",
            InnerRoomVersionId::Custom(version) => version,
        }
    }
}

impl Display for RoomVersionId {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_ref())
    }
}

#[cfg(feature = "serde")]
impl Serialize for RoomVersionId {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.as_ref())
    }
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for RoomVersionId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        crate::deserialize_id(deserializer, "a Matrix room version ID as a string")
    }
}

/// Attempts to create a new Matrix room version ID from a string representation.
fn try_from<S>(room_version_id: S) -> Result<RoomVersionId, Error>
where
    S: AsRef<str> + Into<Box<str>>,
{
    let version = match room_version_id.as_ref() {
        "1" => RoomVersionId(InnerRoomVersionId::Version1),
        "2" => RoomVersionId(InnerRoomVersionId::Version2),
        "3" => RoomVersionId(InnerRoomVersionId::Version3),
        "4" => RoomVersionId(InnerRoomVersionId::Version4),
        "5" => RoomVersionId(InnerRoomVersionId::Version5),
        custom => {
            if custom.is_empty() {
                return Err(Error::MinimumLengthNotSatisfied);
            } else if custom.chars().count() > MAX_CODE_POINTS {
                return Err(Error::MaximumLengthExceeded);
            } else {
                RoomVersionId(InnerRoomVersionId::Custom(room_version_id.into()))
            }
        }
    };

    Ok(version)
}

impl TryFrom<&str> for RoomVersionId {
    type Error = crate::error::Error;

    fn try_from(s: &str) -> Result<Self, Error> {
        try_from(s)
    }
}

impl TryFrom<String> for RoomVersionId {
    type Error = crate::error::Error;

    fn try_from(s: String) -> Result<Self, Error> {
        try_from(s)
    }
}

impl PartialEq<&str> for RoomVersionId {
    fn eq(&self, other: &&str) -> bool {
        self.as_ref() == *other
    }
}

impl PartialEq<RoomVersionId> for &str {
    fn eq(&self, other: &RoomVersionId) -> bool {
        *self == other.as_ref()
    }
}

impl PartialEq<String> for RoomVersionId {
    fn eq(&self, other: &String) -> bool {
        self.as_ref() == other
    }
}

impl PartialEq<RoomVersionId> for String {
    fn eq(&self, other: &RoomVersionId) -> bool {
        self == other.as_ref()
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryFrom;

    #[cfg(feature = "serde")]
    use serde_json::{from_str, to_string};

    use super::RoomVersionId;
    use crate::error::Error;

    #[test]
    fn valid_version_1_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("1")
                .expect("Failed to create RoomVersionId.")
                .as_ref(),
            "1"
        );
    }

    #[test]
    fn valid_version_2_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("2")
                .expect("Failed to create RoomVersionId.")
                .as_ref(),
            "2"
        );
    }

    #[test]
    fn valid_version_3_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("3")
                .expect("Failed to create RoomVersionId.")
                .as_ref(),
            "3"
        );
    }

    #[test]
    fn valid_version_4_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("4")
                .expect("Failed to create RoomVersionId.")
                .as_ref(),
            "4"
        );
    }

    #[test]
    fn valid_version_5_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("5")
                .expect("Failed to create RoomVersionId.")
                .as_ref(),
            "5"
        );
    }

    #[test]
    fn valid_custom_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("io.ruma.1")
                .expect("Failed to create RoomVersionId.")
                .as_ref(),
            "io.ruma.1"
        );
    }

    #[test]
    fn empty_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from(""),
            Err(Error::MinimumLengthNotSatisfied)
        );
    }

    #[test]
    fn over_max_code_point_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("0123456789012345678901234567890123456789"),
            Err(Error::MaximumLengthExceeded)
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn serialize_official_room_id() {
        assert_eq!(
            to_string(&RoomVersionId::try_from("1").expect("Failed to create RoomVersionId."))
                .expect("Failed to convert RoomVersionId to JSON."),
            r#""1""#
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn deserialize_official_room_id() {
        let deserialized =
            from_str::<RoomVersionId>(r#""1""#).expect("Failed to convert RoomVersionId to JSON.");

        assert!(deserialized.is_version_1());
        assert!(deserialized.is_official());

        assert_eq!(
            deserialized,
            RoomVersionId::try_from("1").expect("Failed to create RoomVersionId.")
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn serialize_custom_room_id() {
        assert_eq!(
            to_string(
                &RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.")
            )
            .expect("Failed to convert RoomVersionId to JSON."),
            r#""io.ruma.1""#
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn deserialize_custom_room_id() {
        let deserialized = from_str::<RoomVersionId>(r#""io.ruma.1""#)
            .expect("Failed to convert RoomVersionId to JSON.");

        assert!(deserialized.is_custom());

        assert_eq!(
            deserialized,
            RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.")
        );
    }

    #[test]
    fn constructors() {
        assert!(RoomVersionId::version_1().is_version_1());
        assert!(RoomVersionId::version_2().is_version_2());
        assert!(RoomVersionId::version_3().is_version_3());
        assert!(RoomVersionId::version_4().is_version_4());
        assert!(RoomVersionId::version_5().is_version_5());
        assert!(RoomVersionId::custom("foo".into()).is_custom());
    }

    #[test]
    #[allow(clippy::cognitive_complexity)]
    fn predicate_methods() {
        let version_1 = RoomVersionId::try_from("1").expect("Failed to create RoomVersionId.");
        let version_2 = RoomVersionId::try_from("2").expect("Failed to create RoomVersionId.");
        let version_3 = RoomVersionId::try_from("3").expect("Failed to create RoomVersionId.");
        let version_4 = RoomVersionId::try_from("4").expect("Failed to create RoomVersionId.");
        let version_5 = RoomVersionId::try_from("5").expect("Failed to create RoomVersionId.");
        let custom = RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.");

        assert!(version_1.is_version_1());
        assert!(version_2.is_version_2());
        assert!(version_3.is_version_3());
        assert!(version_4.is_version_4());
        assert!(version_5.is_version_5());

        assert!(!version_1.is_version_2());
        assert!(!version_1.is_version_3());
        assert!(!version_1.is_version_4());
        assert!(!version_1.is_version_5());

        assert!(version_1.is_official());
        assert!(version_2.is_official());
        assert!(version_3.is_official());
        assert!(version_4.is_official());
        assert!(version_5.is_official());

        assert!(!version_1.is_custom());
        assert!(!version_2.is_custom());
        assert!(!version_3.is_custom());
        assert!(!version_4.is_custom());
        assert!(!version_5.is_custom());

        assert!(custom.is_custom());
        assert!(!custom.is_official());
        assert!(!custom.is_version_1());
        assert!(!custom.is_version_2());
        assert!(!custom.is_version_3());
        assert!(!custom.is_version_4());
        assert!(!custom.is_version_5());
    }
}
<|endoftext|>


<commit_before>use std::convert::{From, Into};
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;
use std::hash::Hash;
use std::path::PathBuf;
use std::result::Result;
use std::str::FromStr;

use regex::Regex;

use storage::file::id_type::FileIDType;
use storage::file::hash::FileHash;

#[derive(Clone)]
#[derive(Hash)]
#[derive(Eq)]
#[derive(PartialEq)]
pub struct FileID {
    id:         FileHash,
    id_type:    FileIDType,
}

impl FileID {

    pub fn new(id_type: FileIDType, id: FileHash) -> FileID {
        FileID {
            id: id,
            id_type: id_type,
        }
    }

    pub fn get_type(&self) -> FileIDType {
        self.id_type.clone()
    }

    pub fn get_id(&self) -> FileHash {
        self.id.clone()
    }

    pub fn parse(string: &String) -> Option<FileID> {
        // we assume that it is an path
        let regex = Regex::new(r"([:alnum:]*)-([:upper:]*)-([A-Za-z0-9-_]*)\.(.*)").unwrap();
        let s = string.split("/").last().unwrap_or("");

        debug!("Regex build: {:?}", regex);
        debug!("Matching string: '{}'", s);
        regex.captures(s).and_then(|capts| {
            // first one is the whole string, index 1-N are the matches.
            if capts.len() != 5 {
                debug!("Matches, but not expected number of groups");
                return None;
            }
            debug!("Matches: {}", capts.len());

            let modname     = capts.at(1).unwrap();
            let hashname    = capts.at(2).unwrap();
            let mut hash    = capts.at(3).unwrap();

            debug!("Destructure FilePath to ID:");
            debug!("                  FilePath: {:?}", s);
            debug!("               Module Name: {:?}", modname);
            debug!("                 Hash Name: {:?}", hashname);
            debug!("                      Hash: {:?}", hash);

            FileIDType::from_str(hashname).map(|idtype| {
                Some(FileID {
                    id: FileHash::from(hash),
                    id_type: idtype,
                })
            }).ok()
        }).unwrap_or({
            debug!("Did not match");
            debug!("It is no path, actually. So we assume it is an ID already");
            None
        })
    }

}

impl Debug for FileID {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileID[{:?}]: {:?}",
               self.id_type,
               self.id);
        Ok(())
    }

}

impl Display for FileID {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileID[{:?}]: {:?}",
               self.id_type,
               self.id);
        Ok(())
    }

}

impl Into<String> for FileID {

    fn into(self) -> String {
        let typestr : String = self.id_type.into();
        let idstr   : String = self.id.into();
        typestr + "-" + &idstr[..]
    }
}

#[cfg(test)]
mod test {

    use super::{FileID, FileIDType};

    #[test]
    fn file_id_from_string() {
        setup_logger();

        let s1 = String::from("/home/user/testmodule-UUID-some-id.imag");
        let s2 = String::from("/home/user/testmodule-UUID-some-id.extension.imag");
        let s3 = String::from("/home/user/testmodule-NOHASH-some-id.imag");

        let id1 = FileID::from(s1);
        let id2 = FileID::from(s2);
        let id3 = FileID::from(s3);

        println!("Id 1 : {:?}", id1);
        println!("Id 2 : {:?}", id2);
        println!("Id 3 : {:?}", id3);

        assert_eq!(FileIDType::UUID, id1.get_type());
        assert_eq!(FileIDType::UUID, id2.get_type());
        assert_eq!(FileIDType::NONE, id3.get_type());

        let f1 : String = id1.into();
        let f2 : String = id2.into();
        let f3 : String = id3.into();

        assert_eq!(String::from("some-id"), f1);
        assert_eq!(String::from("some-id"), f2);
        assert_eq!(String::from("INVALID"), f3);
    }

    fn setup_logger() {
        extern crate log;
        use log::{LogLevelFilter, set_logger};
        use runtime::ImagLogger;

        log::set_logger(|max_log_lvl| {
            let lvl = LogLevelFilter::Debug;
            max_log_lvl.set(lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        });
        debug!("Init logger for test");
    }

}

<commit_msg>Add debug output to FileID::parse()<commit_after>use std::convert::{From, Into};
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;
use std::hash::Hash;
use std::path::PathBuf;
use std::result::Result;
use std::str::FromStr;

use regex::Regex;

use storage::file::id_type::FileIDType;
use storage::file::hash::FileHash;

#[derive(Clone)]
#[derive(Hash)]
#[derive(Eq)]
#[derive(PartialEq)]
pub struct FileID {
    id:         FileHash,
    id_type:    FileIDType,
}

impl FileID {

    pub fn new(id_type: FileIDType, id: FileHash) -> FileID {
        FileID {
            id: id,
            id_type: id_type,
        }
    }

    pub fn get_type(&self) -> FileIDType {
        self.id_type.clone()
    }

    pub fn get_id(&self) -> FileHash {
        self.id.clone()
    }

    pub fn parse(string: &String) -> Option<FileID> {
        // we assume that it is an path
        let regex = Regex::new(r"([:alnum:]*)-([:upper:]*)-([A-Za-z0-9-_]*)\.(.*)").unwrap();
        let s = string.split("/").last().unwrap_or("");

        debug!("Regex build: {:?}", regex);
        debug!("Matching string: '{}'", s);
        regex.captures(s).and_then(|capts| {
            // first one is the whole string, index 1-N are the matches.
            if capts.len() != 5 {
                debug!("Matches, but not expected number of groups");
                return None;
            }
            debug!("Matches: {}", capts.len());

            let modname     = capts.at(1).unwrap();
            let hashname    = capts.at(2).unwrap();
            let mut hash    = capts.at(3).unwrap();

            debug!("Destructure FilePath to ID:");
            debug!("                  FilePath: {:?}", s);
            debug!("               Module Name: {:?}", modname);
            debug!("                 Hash Name: {:?}", hashname);
            debug!("                      Hash: {:?}", hash);

            FileIDType::from_str(hashname).map(|idtype| {
                debug!("ID type = {:?}", idtype);
                Some(FileID {
                    id: FileHash::from(hash),
                    id_type: idtype,
                })
            }).ok()
        }).unwrap_or({
            debug!("Did not match");
            debug!("It is no path, actually. So we assume it is an ID already");
            None
        })
    }

}

impl Debug for FileID {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileID[{:?}]: {:?}",
               self.id_type,
               self.id);
        Ok(())
    }

}

impl Display for FileID {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileID[{:?}]: {:?}",
               self.id_type,
               self.id);
        Ok(())
    }

}

impl Into<String> for FileID {

    fn into(self) -> String {
        let typestr : String = self.id_type.into();
        let idstr   : String = self.id.into();
        typestr + "-" + &idstr[..]
    }
}

#[cfg(test)]
mod test {

    use super::{FileID, FileIDType};

    #[test]
    fn file_id_from_string() {
        setup_logger();

        let s1 = String::from("/home/user/testmodule-UUID-some-id.imag");
        let s2 = String::from("/home/user/testmodule-UUID-some-id.extension.imag");
        let s3 = String::from("/home/user/testmodule-NOHASH-some-id.imag");

        let id1 = FileID::from(s1);
        let id2 = FileID::from(s2);
        let id3 = FileID::from(s3);

        println!("Id 1 : {:?}", id1);
        println!("Id 2 : {:?}", id2);
        println!("Id 3 : {:?}", id3);

        assert_eq!(FileIDType::UUID, id1.get_type());
        assert_eq!(FileIDType::UUID, id2.get_type());
        assert_eq!(FileIDType::NONE, id3.get_type());

        let f1 : String = id1.into();
        let f2 : String = id2.into();
        let f3 : String = id3.into();

        assert_eq!(String::from("some-id"), f1);
        assert_eq!(String::from("some-id"), f2);
        assert_eq!(String::from("INVALID"), f3);
    }

    fn setup_logger() {
        extern crate log;
        use log::{LogLevelFilter, set_logger};
        use runtime::ImagLogger;

        log::set_logger(|max_log_lvl| {
            let lvl = LogLevelFilter::Debug;
            max_log_lvl.set(lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        });
        debug!("Init logger for test");
    }

}

<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Taxicab_numbers
// not_tested

use std::collections::PriorityQueue;
use std::num::pow;

/// A type to represent a pair-sum of cubes.
/// value = a^3 + b^3
#[deriving(Eq, Ord)]
struct SumCubes {
    a: u64,
    b: u64,
    value: u64
}

impl SumCubes {
    fn new(a: u64, b: u64) -> SumCubes {
        SumCubes{ a: a, b: b, value: pow(a, 3) + pow(b, 3) }
    }
}

impl PartialEq for SumCubes {
    fn eq(&self, other: &SumCubes) -> bool {
        self.value == other.value
    }
}

impl PartialOrd for SumCubes {
    fn partial_cmp(&self, other: &SumCubes) -> Option<Ordering> {
        // Comparison is reversed to make PriorityQueue behave like a min-heap
        other.value.partial_cmp(&self.value)
    }
}

fn main() {

    // Go through all pair-sums of cubes in increasing order

    // Use a priority queue to do it efficiently
    let mut pq = PriorityQueue::new();

    // Start with 1^3 + 1^3
    pq.push(SumCubes::new(1, 1));

    let mut at: uint = 1;           // The number of the result we're currently at
    let mut ways = Vec::new();      // All the ways we can express the current
                                    // value as a sum of cubes
    ways.push(SumCubes::new(0, 0)); // Just a sentinel value

    loop {
        let cur = pq.pop().unwrap();

        if cur.value == ways[0].value {
            // If the current sum is the same as the last one,
            // then we found another way to express the current value
            ways.push(cur);
        } else {
            if ways.len() > 1 {
                // If we can express the last value in more than one ways
                if (1 <= at && at <= 25) || (2000 <= at && at <= 2006) {

                    // Then output it
                    print!("{:>4u}:{:>10u}", at, ways[0].value);
                    for &SumCubes{ a, b, value } in ways.iter() {
                        print!(" = {:>4u}^3 + {:>4u}^3", a, b);
                    }

                    print!("\n");
                }

                if at == 2006 {
                    break;
                }

                at += 1;
            }

            ways.clear();
            ways.push(cur);
        }

        // Populate the priority queue with more sums
        pq.push(SumCubes::new(cur.a+1, cur.b));
        if cur.a == cur.b {
            pq.push(SumCubes::new(cur.a+1, cur.b+1));
        }
    }
}

<commit_msg>Create an iterator of Taxicab numbers, and other fixes<commit_after>// http://rosettacode.org/wiki/Taxicab_numbers
use std::collections::PriorityQueue;
use std::num::pow;

/// A type to represent a pair-sum of cubes.
/// value = a^3 + b^3
#[deriving(PartialEq, Eq)]
struct SumCubes {
    a: u64,
    b: u64,
    value: u64,
}

impl SumCubes {
    fn new(a: u64, b: u64) -> SumCubes {
        SumCubes{ value: pow(a, 3) + pow(b, 3), a: a, b: b }
    }
}

impl PartialOrd for SumCubes {
    fn partial_cmp(&self, other: &SumCubes) -> Option<Ordering> {
        // Comparison is reversed to make PriorityQueue behave like a min-heap
        (other.value, other.a, other.b).partial_cmp(&(self.value, self.a, self.b))
    }
}

impl Ord for SumCubes {
    fn cmp(&self, other: &SumCubes) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

/// An iterator through all Taxicab numbers
struct TaxicabNumbers {
    // Use a priority queue to iterate through sums
    // of cubes efficiently in increasing order
    pq: PriorityQueue<SumCubes>,
}

impl TaxicabNumbers {
    fn new() -> TaxicabNumbers {
        let mut res = TaxicabNumbers{ pq: PriorityQueue::new() };
        res.pq.push(SumCubes::new(1, 1)); // Start with 1^3 + 1^3
        res
    }
}

impl Iterator<Vec<SumCubes>> for TaxicabNumbers {
    fn next(&mut self) -> Option<Vec<SumCubes>> {
        let mut ways = Vec::new();      // All the ways we can express the current
                                        // value as a sum of cubes
        ways.push(SumCubes::new(0, 0)); // Just a sentinel value

        loop {
            let nxt = self.pq.pop().unwrap();
            if nxt.value == ways[0].value {
                // If the next sum is the same as the current one,
                // then we found another way to express the current value
                ways.push(nxt);
            } else if ways.len() > 1 {
                // If we can express the current value in more than one ways,
                // then it's a Taxicab number
                self.pq.push(nxt);
                return Some(ways);
            } else {
                ways.clear();
                ways.push(nxt);
            }

            // Populate the priority queue with more sums
            self.pq.push(SumCubes::new(nxt.a+1, nxt.b));
            if nxt.a == nxt.b {
                self.pq.push(SumCubes::new(nxt.a+1, nxt.b+1));
            }
        }
    }
}

#[cfg(not(test))]
fn main() {
    use std::iter::count;
    let numbers = TaxicabNumbers::new();
    for (at, ways) in count(1u, 1).zip(numbers.take(2006))
                                  .filter(|&(at, _)| at <= 25 || at >= 2000) {
        print!("{:>4u}:{:>10u}", at, ways[0].value);
        for &SumCubes{ a, b, value } in ways.iter() {
            print!(" = {:>4u}^3 + {:>4u}^3", a, b);
        }
        print!("\n");
    }
}

#[test]
fn test_taxicab_numbers() {
    // A001235 on OEIS
    let seq = [1729u64,4104,13832,20683,32832,39312,40033,46683,
               64232,65728,110656,110808,134379,149389,165464,
               171288,195841,216027,216125,262656,314496,320264,
               327763,373464,402597,439101,443889,513000,513856,
               515375,525824,558441,593047,684019,704977];

    for (&expected, ways) in seq.iter().zip(TaxicabNumbers::new()) {
        assert!(ways.len() > 1);
        for &SumCubes{value, ..} in ways.iter() {
            assert_eq!(value, expected);
        }
    }
}

<|endoftext|>


<commit_before>mod add;
mod build;
mod cmin;
mod fmt;
mod init;
mod list;
mod run;
mod tmin;

pub use self::{
    add::Add, build::Build, cmin::Cmin, fmt::Fmt, init::Init, list::List, run::Run, tmin::Tmin,
};

use std::fmt as stdfmt;
use std::str::FromStr;
use structopt::StructOpt;

#[derive(Debug, Clone, Copy)]
pub enum Sanitizer {
    Address,
    Leak,
    Memory,
    Thread,
    None,
}

impl stdfmt::Display for Sanitizer {
    fn fmt(&self, f: &mut stdfmt::Formatter) -> stdfmt::Result {
        write!(
            f,
            "{}",
            match self {
                Sanitizer::Address => "address",
                Sanitizer::Leak => "leak",
                Sanitizer::Memory => "memory",
                Sanitizer::Thread => "thread",
                Sanitizer::None => "",
            }
        )
    }
}

impl FromStr for Sanitizer {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "address" => Ok(Sanitizer::Address),
            "leak" => Ok(Sanitizer::Leak),
            "memory" => Ok(Sanitizer::Memory),
            "thread" => Ok(Sanitizer::Thread),
            "none" => Ok(Sanitizer::None),
            _ => Err(format!("unknown sanitizer: {}", s)),
        }
    }
}

#[derive(Clone, Debug, StructOpt)]
pub struct BuildOptions {
    #[structopt(short = "D", long = "dev", conflicts_with = "release")]
    /// Build artifacts in development mode, without optimizations
    pub dev: bool,

    #[structopt(short = "O", long = "release", conflicts_with = "debug")]
    /// Build artifacts in release mode, with optimizations
    pub release: bool,

    #[structopt(short = "a", long = "debug-assertions")]
    /// Build artifacts with debug assertions and overflow checks enabled (default if not -O)
    pub debug_assertions: bool,

    /// Build target with verbose output from `cargo build`
    #[structopt(short = "v", long = "verbose")]
    pub verbose: bool,

    #[structopt(long = "no-default-features")]
    /// Build artifacts with default Cargo features disabled
    pub no_default_features: bool,

    #[structopt(
        long = "all-features",
        conflicts_with = "no-default-features",
        conflicts_with = "features"
    )]
    /// Build artifacts with all Cargo features enabled
    pub all_features: bool,

    #[structopt(long = "features")]
    /// Build artifacts with given Cargo feature enabled
    pub features: Option<String>,

    #[structopt(
        short = "s",
        long = "sanitizer",
        possible_values(&["address", "leak", "memory", "thread", "none"]),
        default_value = "address",
    )]
    /// Use a specific sanitizer
    pub sanitizer: Sanitizer,

    #[structopt(
        name = "triple",
        long = "target",
        default_value(crate::utils::default_target())
    )]
    /// Target triple of the fuzz target
    pub triple: String,

    #[structopt(short = "Z", value_name = "FLAG")]
    /// Unstable (nightly-only) flags to Cargo
    pub unstable_flags: Vec<String>,
}
<commit_msg>Fix option name in 'conflicts' field<commit_after>mod add;
mod build;
mod cmin;
mod fmt;
mod init;
mod list;
mod run;
mod tmin;

pub use self::{
    add::Add, build::Build, cmin::Cmin, fmt::Fmt, init::Init, list::List, run::Run, tmin::Tmin,
};

use std::fmt as stdfmt;
use std::str::FromStr;
use structopt::StructOpt;

#[derive(Debug, Clone, Copy)]
pub enum Sanitizer {
    Address,
    Leak,
    Memory,
    Thread,
    None,
}

impl stdfmt::Display for Sanitizer {
    fn fmt(&self, f: &mut stdfmt::Formatter) -> stdfmt::Result {
        write!(
            f,
            "{}",
            match self {
                Sanitizer::Address => "address",
                Sanitizer::Leak => "leak",
                Sanitizer::Memory => "memory",
                Sanitizer::Thread => "thread",
                Sanitizer::None => "",
            }
        )
    }
}

impl FromStr for Sanitizer {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "address" => Ok(Sanitizer::Address),
            "leak" => Ok(Sanitizer::Leak),
            "memory" => Ok(Sanitizer::Memory),
            "thread" => Ok(Sanitizer::Thread),
            "none" => Ok(Sanitizer::None),
            _ => Err(format!("unknown sanitizer: {}", s)),
        }
    }
}

#[derive(Clone, Debug, StructOpt)]
pub struct BuildOptions {
    #[structopt(short = "D", long = "dev", conflicts_with = "release")]
    /// Build artifacts in development mode, without optimizations
    pub dev: bool,

    #[structopt(short = "O", long = "release", conflicts_with = "dev")]
    /// Build artifacts in release mode, with optimizations
    pub release: bool,

    #[structopt(short = "a", long = "debug-assertions")]
    /// Build artifacts with debug assertions and overflow checks enabled (default if not -O)
    pub debug_assertions: bool,

    /// Build target with verbose output from `cargo build`
    #[structopt(short = "v", long = "verbose")]
    pub verbose: bool,

    #[structopt(long = "no-default-features")]
    /// Build artifacts with default Cargo features disabled
    pub no_default_features: bool,

    #[structopt(
        long = "all-features",
        conflicts_with = "no-default-features",
        conflicts_with = "features"
    )]
    /// Build artifacts with all Cargo features enabled
    pub all_features: bool,

    #[structopt(long = "features")]
    /// Build artifacts with given Cargo feature enabled
    pub features: Option<String>,

    #[structopt(
        short = "s",
        long = "sanitizer",
        possible_values(&["address", "leak", "memory", "thread", "none"]),
        default_value = "address",
    )]
    /// Use a specific sanitizer
    pub sanitizer: Sanitizer,

    #[structopt(
        name = "triple",
        long = "target",
        default_value(crate::utils::default_target())
    )]
    /// Target triple of the fuzz target
    pub triple: String,

    #[structopt(short = "Z", value_name = "FLAG")]
    /// Unstable (nightly-only) flags to Cargo
    pub unstable_flags: Vec<String>,
}
<|endoftext|>


<commit_before>//! A signal processing framework for making music with rust.
//!
//! `oxcable` is designed with simple but powerful abstractions, with minimal
//! performance loss, while functioning in real-time.
//!
//! `oxcable` seeks to provide the basic building blocks necessary to build
//! digital instruments and effects, and provide the tools to chain these
//! devices together quickly and easily.

#![crate_name = "oxcable"]

extern crate byteorder;
extern crate num;
extern crate rand;

pub mod adsr;
pub mod chain;
pub mod delay;
pub mod dynamics;
pub mod filters;
pub mod graph;
pub mod io;
pub mod mixers;
pub mod oscillator;
pub mod reverb;
pub mod tick;
pub mod types;
pub mod utils;
pub mod voice_array;
<commit_msg>Expand base level documentation<commit_after>//! A signal processing framework for making music with rust.
//!
//! `oxcable` is designed with simple but powerful abstractions, with minimal
//! performance loss, while functioning in real-time.
//!
//! `oxcable` seeks to provide the basic building blocks necessary to build
//! digital instruments and effects, and provide the tools to chain these
//! devices together quickly and easily.
//!
//! # Getting started
//!
//! Let's start with a simple example. This script will read from your
//! computer's microphone and feed the audio back ito your computer's speakers
//! or headphones in an infinite loop:
//!
//! ```
//! extern crate oxcable;
//! use oxcable::chain::{DeviceChain, Tick};
//! use oxcable::io::audio::AudioEngine;
//!
//! fn main() {
//!     let engine = AudioEngine::with_buffer_size(256).unwrap();
//!     let mut chain = DeviceChain::from(
//!         engine.default_input(1).unwrap()
//!     ).into(
//!         engine.default_output(1).unwrap()
//!     );
//! # }
//! # // wrap tick_forever() in a function that gets compiled by not run by
//! # //doctest
//! # fn dummy(chain: &mut DeviceChain) {
//!     chain.tick_forever();
//! }
//! ```
//!
//! # Devices
//!
//! Defining an audio device can be done by implenting the
//! [`AudioDevice` trait](types/trait.AudioDevice.html). This adheres to
//! a simple interface.
//!
//! Let's define a very simple audio device: one that simply passes its input
//! straight to the output. This can be done in just a few lines:
//!
//! ```
//! use oxcable::types::{AudioDevice, Sample, Time};
//!
//! struct IdentityFilter;
//! impl AudioDevice for IdentityFilter {
//!     fn num_inputs(&self) -> usize { 1 }
//!     fn num_outputs(&self) -> usize { 1 }
//!     fn tick(&mut self, _: Time, inputs: &[Sample], outputs: &mut[Sample]) {
//!         outputs[0] = inputs[0];
//!     }
//! }
//! ```
//!
//! Once we've defined a device, it is simple to use the device in isolation.
//! Say I want to test my filter. I can manually call tick a few times to
//! generate outputs:
//!
//! ```
//! # use oxcable::types::{AudioDevice, Sample, Time};
//! # struct IdentityFilter;
//! # impl AudioDevice for IdentityFilter {
//! #     fn num_inputs(&self) -> usize { 1 }
//! #     fn num_outputs(&self) -> usize { 1 }
//! #     fn tick(&mut self, _: Time, inputs: &[Sample], outputs: &mut[Sample]) {
//! #         outputs[0] = inputs[0];
//! #     }
//! # }
//! #
//! let mut input = [0.0];
//! let mut output = [0.0];
//! let mut filter = IdentityFilter;
//!
//! for i in 0..8 {
//!     input[0] = i as f32;
//!     filter.tick(i, &input, &mut output);
//!     assert_eq!(input[0], output[0]);
//! }
//! ```
//!
//! By adhering to the `AudioDevice` trait, however, this new device will drop
//! straight into generic containers like [`DeviceChain`](chain/index.html) or
//! [`DeviceGraph`](graph/index.html).

#![crate_name = "oxcable"]

extern crate byteorder;
extern crate num;
extern crate rand;

pub mod adsr;
pub mod chain;
pub mod delay;
pub mod dynamics;
pub mod filters;
pub mod graph;
pub mod io;
pub mod mixers;
pub mod oscillator;
pub mod reverb;
pub mod tick;
pub mod types;
pub mod utils;
pub mod voice_array;
<|endoftext|>