<commit_before>use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use fnv::{FnvHashMap, FnvHashSet};
use {Command, Error, Record};

const ORIGIN: usize = 0;

/// A history of commands.
#[derive(Debug)]
pub struct History<R> {
    id: usize,
    parent: usize,
    next: usize,
    record: Record<R>,
    branches: FnvHashMap<usize, Branch<R>>,
}

impl<R> History<R> {
    /// Returns a new history.
    #[inline]
    pub fn new(receiver: impl Into<R>) -> History<R> {
        History {
            id: ORIGIN,
            parent: ORIGIN,
            next: 1,
            record: Record::new(receiver),
            branches: FnvHashMap::default(),
        }
    }

    /// Pushes the command to the top of the history and executes its [`apply`] method.
    /// The command is merged with the previous top command if they have the same [`id`].
    ///
    /// # Errors
    /// If an error occur when executing [`apply`] the error is returned together with the command.
    ///
    /// [`apply`]: trait.Command.html#tymethod.apply
    /// [`id`]: trait.Command.html#method.id
    #[inline]
    pub fn apply(&mut self, cmd: impl Command<R> + 'static) -> Result<Option<usize>, Error<R>>
    where
        R: 'static,
    {
        let cursor = self.record.cursor();
        let commands = self.record.apply(cmd)?;
        let commands: Vec<_> = commands.collect();
        if !commands.is_empty() {
            let id = self.next;
            self.next += 1;
            self.branches.insert(
                id,
                Branch {
                    parent: self.id,
                    cursor,
                    commands,
                },
            );
            Ok(Some(id))
        } else {
            Ok(None)
        }
    }

    /// Calls the [`undo`] method for the active command and sets the previous one as the new active one.
    ///
    /// # Errors
    /// If an error occur when executing [`undo`] the error is returned together with the command.
    ///
    /// [`undo`]: trait.Command.html#tymethod.undo
    #[inline]
    #[must_use]
    pub fn undo(&mut self) -> Option<Result<(), Error<R>>> {
        self.record.undo()
    }

    /// Calls the [`redo`] method for the active command and sets the next one as the
    /// new active one.
    ///
    /// # Errors
    /// If an error occur when executing [`redo`] the error is returned together with the command.
    ///
    /// [`redo`]: trait.Command.html#method.redo
    #[inline]
    #[must_use]
    pub fn redo(&mut self) -> Option<Result<(), Error<R>>> {
        self.record.redo()
    }

    /// Jumps to the command in `branch` at `cursor`.
    #[inline]
    #[must_use]
    pub fn jump_to(&mut self, mut branch: usize, cursor: usize) -> Option<Result<(), Error<R>>>
    where
        R: 'static,
    {
        if self.id == branch {
            return self.record.jump_to(cursor);
        }

        // All visited nodes.
        let visited = {
            let mut visited = FnvHashSet::default();
            // Find the path from `dest` to `ORIGIN`.
            let mut dest = self.branches.get(&branch)?;
            while dest.parent != ORIGIN {
                assert!(visited.insert(dest.parent));
                dest = self.branches.get(&dest.parent).unwrap();
            }
            visited
        };

        let mut path = Vec::with_capacity(visited.len() + self.record.len());
        // Find the path from `start` to the lowest common ancestor of `dest`.
        if self.id != ORIGIN {
            let mut start = self.branches.remove(&self.parent).unwrap();
            branch = start.parent;
            while !visited.contains(&branch) {
                path.push(start);
                start = self.branches.remove(&branch).unwrap();
                branch = start.parent;
            }
        }

        // Find the path from `dest` to the lowest common ancestor of `start`.
        let mut dest = self.branches.remove(&branch)?;
        branch = dest.parent;
        let len = path.len();
        path.push(dest);
        let last = path.last().map_or(ORIGIN, |last| last.parent);
        while branch != last {
            dest = self.branches.remove(&branch).unwrap();
            branch = dest.parent;
            path.push(dest);
        }
        path[len..].reverse();

        // Walk the path from `start` to `dest`.
        for dest in path {
            // Move to `dest.cursor` either by undoing or redoing.
            if let Err(err) = self.record.jump_to(dest.cursor).unwrap() {
                return Some(Err(err));
            }
            // Apply the commands in the branch and move older commands into their own branch.
            for cmd in dest.commands {
                let cursor = self.record.cursor();
                let commands = match self.record.apply(cmd) {
                    Ok(commands) => commands,
                    Err(err) => return Some(Err(err)),
                };
                let commands: Vec<_> = commands.collect();
                if !commands.is_empty() {
                    self.branches.insert(
                        self.id,
                        Branch {
                            parent: dest.parent,
                            cursor,
                            commands,
                        },
                    );
                    self.id = dest.parent;
                }
            }
        }

        Some(Ok(()))
    }
}

impl<R: Default> Default for History<R> {
    #[inline]
    fn default() -> History<R> {
        History::new(R::default())
    }
}

impl<R> From<R> for History<R> {
    #[inline]
    fn from(receiver: R) -> Self {
        History::new(receiver)
    }
}

struct Branch<R> {
    parent: usize,
    cursor: usize,
    commands: Vec<Box<dyn Command<R> + 'static>>,
}

impl<R> Debug for Branch<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Branch")
            .field("parent", &self.parent)
            .field("cursor", &self.cursor)
            .field("commands", &self.commands)
            .finish()
    }
}

/// Builder for a history.
#[derive(Debug)]
pub struct HistoryBuilder<R> {
    receiver: PhantomData<R>,
}

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

    #[derive(Debug)]
    struct Add(char);

    impl Command<String> for Add {
        fn apply(&mut self, receiver: &mut String) -> Result<(), Box<dyn Error>> {
            receiver.push(self.0);
            Ok(())
        }

        fn undo(&mut self, receiver: &mut String) -> Result<(), Box<dyn Error>> {
            self.0 = receiver.pop().ok_or("`receiver` is empty")?;
            Ok(())
        }
    }

    #[test]
    fn jump_to() {
        let mut history = History::default();
        history.apply(Add('a')).unwrap();
        history.apply(Add('b')).unwrap();
        history.apply(Add('c')).unwrap();
        history.apply(Add('d')).unwrap();
        history.apply(Add('e')).unwrap();

        history.undo().unwrap().unwrap();
        history.undo().unwrap().unwrap();

        let b = history.apply(Add('f')).unwrap().unwrap();
        history.apply(Add('g')).unwrap();

        history.jump_to(b, 5).unwrap().unwrap();
    }
}
<commit_msg>Use Option<usize> for parent in History<commit_after>use fnv::{FnvHashMap, FnvHashSet};
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use {Command, Error, Record};

const ORIGIN: usize = 0;

/// A history of commands.
#[derive(Debug)]
pub struct History<R> {
    id: usize,
    next: usize,
    parent: Option<usize>,
    record: Record<R>,
    branches: FnvHashMap<usize, Branch<R>>,
}

impl<R> History<R> {
    /// Returns a new history.
    #[inline]
    pub fn new(receiver: impl Into<R>) -> History<R> {
        History {
            id: ORIGIN,
            next: 1,
            parent: None,
            record: Record::new(receiver),
            branches: FnvHashMap::default(),
        }
    }

    /// Pushes the command to the top of the history and executes its [`apply`] method.
    /// The command is merged with the previous top command if they have the same [`id`].
    ///
    /// # Errors
    /// If an error occur when executing [`apply`] the error is returned together with the command.
    ///
    /// [`apply`]: trait.Command.html#tymethod.apply
    /// [`id`]: trait.Command.html#method.id
    #[inline]
    pub fn apply(&mut self, cmd: impl Command<R> + 'static) -> Result<Option<usize>, Error<R>>
    where
        R: 'static,
    {
        let cursor = self.record.cursor();
        let commands = self.record.apply(cmd)?;
        let commands: Vec<_> = commands.collect();
        if !commands.is_empty() {
            let id = self.next;
            self.next += 1;
            self.branches.insert(
                id,
                Branch {
                    parent: self.id,
                    cursor,
                    commands,
                },
            );
            Ok(Some(id))
        } else {
            Ok(None)
        }
    }

    /// Calls the [`undo`] method for the active command and sets the previous one as the new active one.
    ///
    /// # Errors
    /// If an error occur when executing [`undo`] the error is returned together with the command.
    ///
    /// [`undo`]: trait.Command.html#tymethod.undo
    #[inline]
    #[must_use]
    pub fn undo(&mut self) -> Option<Result<(), Error<R>>> {
        self.record.undo()
    }

    /// Calls the [`redo`] method for the active command and sets the next one as the
    /// new active one.
    ///
    /// # Errors
    /// If an error occur when executing [`redo`] the error is returned together with the command.
    ///
    /// [`redo`]: trait.Command.html#method.redo
    #[inline]
    #[must_use]
    pub fn redo(&mut self) -> Option<Result<(), Error<R>>> {
        self.record.redo()
    }

    /// Jumps to the command in `branch` at `cursor`.
    #[inline]
    #[must_use]
    pub fn jump_to(&mut self, mut branch: usize, cursor: usize) -> Option<Result<(), Error<R>>>
    where
        R: 'static,
    {
        if self.id == branch {
            return self.record.jump_to(cursor);
        }

        // All visited nodes.
        let visited = {
            let mut visited =
                FnvHashSet::with_capacity_and_hasher(self.record.capacity(), Default::default());
            // Find the path from `dest` to `ORIGIN`.
            let mut dest = self.branches.get(&branch)?;
            while dest.parent != ORIGIN {
                assert!(visited.insert(dest.parent));
                dest = self.branches.get(&dest.parent).unwrap();
            }
            visited
        };

        let mut path = Vec::with_capacity(visited.len() + self.record.len());
        // Find the path from `start` to the lowest common ancestor of `dest`.
        if let Some(ref parent) = self.parent {
            let mut start = self.branches.remove(parent).unwrap();
            branch = start.parent;
            while !visited.contains(&branch) {
                path.push(start);
                start = self.branches.remove(&branch).unwrap();
                branch = start.parent;
            }
        }

        // Find the path from `dest` to the lowest common ancestor of `start`.
        let mut dest = self.branches.remove(&branch)?;
        branch = dest.parent;
        let len = path.len();
        path.push(dest);
        let last = path.last().map_or(ORIGIN, |last| last.parent);
        while branch != last {
            dest = self.branches.remove(&branch).unwrap();
            branch = dest.parent;
            path.push(dest);
        }
        path[len..].reverse();

        // Walk the path from `start` to `dest`.
        for branch in path {
            // Move to `dest.cursor` either by undoing or redoing.
            if let Err(err) = self.record.jump_to(branch.cursor).unwrap() {
                return Some(Err(err));
            }
            // Apply the commands in the branch and move older commands into their own branch.
            for cmd in branch.commands {
                let cursor = self.record.cursor();
                let commands = match self.record.apply(cmd) {
                    Ok(commands) => commands,
                    Err(err) => return Some(Err(err)),
                };
                let commands: Vec<_> = commands.collect();
                if !commands.is_empty() {
                    self.branches.insert(
                        self.id,
                        Branch {
                            parent: branch.parent,
                            cursor,
                            commands,
                        },
                    );
                    self.parent = if branch.parent == ORIGIN {
                        None
                    } else {
                        Some(self.id)
                    };
                    self.id = branch.parent;
                }
            }
        }

        Some(Ok(()))
    }
}

impl<R: Default> Default for History<R> {
    #[inline]
    fn default() -> History<R> {
        History::new(R::default())
    }
}

impl<R> From<R> for History<R> {
    #[inline]
    fn from(receiver: R) -> Self {
        History::new(receiver)
    }
}

struct Branch<R> {
    parent: usize,
    cursor: usize,
    commands: Vec<Box<dyn Command<R> + 'static>>,
}

impl<R> Debug for Branch<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Branch")
            .field("parent", &self.parent)
            .field("cursor", &self.cursor)
            .field("commands", &self.commands)
            .finish()
    }
}

/// Builder for a history.
#[derive(Debug)]
pub struct HistoryBuilder<R> {
    receiver: PhantomData<R>,
}

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

    #[derive(Debug)]
    struct Add(char);

    impl Command<String> for Add {
        fn apply(&mut self, receiver: &mut String) -> Result<(), Box<dyn Error>> {
            receiver.push(self.0);
            Ok(())
        }

        fn undo(&mut self, receiver: &mut String) -> Result<(), Box<dyn Error>> {
            self.0 = receiver.pop().ok_or("`receiver` is empty")?;
            Ok(())
        }
    }

    #[test]
    fn jump_to() {
        let mut history = History::default();
        history.apply(Add('a')).unwrap();
        history.apply(Add('b')).unwrap();
        history.apply(Add('c')).unwrap();
        history.apply(Add('d')).unwrap();
        history.apply(Add('e')).unwrap();

        history.undo().unwrap().unwrap();
        history.undo().unwrap().unwrap();

        let b = history.apply(Add('f')).unwrap().unwrap();
        history.apply(Add('g')).unwrap();

        history.jump_to(b, 5).unwrap().unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Write;

use api_client;
use common::ui::{Status, UIWriter, UI};
use tabwriter::TabWriter;

use error::{Error, Result};
use {PRODUCT, VERSION};

pub fn start(
    ui: &mut UI,
    bldr_url: &str,
    group_id: Option<&str>,
    origin: Option<&str>,
    limit: usize,
    show_jobs: bool,
) -> Result<()> {
    let api_client =
        api_client::Client::new(bldr_url, PRODUCT, VERSION, None).map_err(Error::APIClient)?;

    if origin.is_some() {
        do_origin_status(ui, &api_client, origin.unwrap(), limit)?;
    } else {
        do_job_group_status(ui, &api_client, group_id.unwrap(), show_jobs)?;
    }

    Ok(())
}

fn do_job_group_status(
    ui: &mut UI,
    api_client: &api_client::Client,
    group_id: &str,
    show_jobs: bool,
) -> Result<()> {
    let gid = match group_id.parse::<i64>() {
        Ok(g) => g,
        Err(e) => {
            ui.fatal(format!("Failed to parse group id: {}", e))?;
            return Err(Error::ParseIntError(e));
        }
    };

    ui.status(
        Status::Determining,
        format!("status of job group {}", group_id),
    )?;

    match api_client.get_schedule(gid, show_jobs) {
        Ok(sr) => {
            let mut tw = TabWriter::new(vec![]);
            write!(&mut tw, "CREATED AT\tGROUP ID\tSTATUS\tIDENT\n").unwrap();
            write!(
                &mut tw,
                "{}\t{}\t{}\t{}\n",
                sr.created_at, sr.id, sr.state, sr.project_name,
            ).unwrap();
            tw.flush().unwrap();
            let mut written = String::from_utf8(tw.into_inner().unwrap()).unwrap();
            println!("\n{}", written);

            if show_jobs && !sr.projects.is_empty() {
                tw = TabWriter::new(vec![]);
                write!(&mut tw, "NAME\tSTATUS\tJOB ID\tIDENT\n").unwrap();
                for p in sr.projects {
                    write!(
                        &mut tw,
                        "{}\t{}\t{}\t{}\n",
                        p.name, p.state, p.job_id, p.ident,
                    ).unwrap();
                }
                written = String::from_utf8(tw.into_inner().unwrap()).unwrap();
                println!("{}", written);
            }
            Ok(())
        }
        Err(e) => Err(Error::ScheduleStatus(e)),
    }
}

fn do_origin_status(
    ui: &mut UI,
    api_client: &api_client::Client,
    origin: &str,
    limit: usize,
) -> Result<()> {
    ui.status(
        Status::Determining,
        format!("status of job groups in {} origin", origin),
    )?;

    match api_client.get_origin_schedule(origin, limit) {
        Ok(sr) => {
            let mut tw = TabWriter::new(vec![]);
            write!(&mut tw, "CREATED AT\tGROUP ID\tSTATUS\tIDENT\n").unwrap();
            for s in sr.iter() {
                write!(
                    &mut tw,
                    "{}\t{}\t{}\t{}\n",
                    s.created_at, s.id, s.state, s.project_name,
                ).unwrap();
            }

            tw.flush().unwrap();
            let written = String::from_utf8(tw.into_inner().unwrap()).unwrap();
            println!("\n{}", written);
            Ok(())
        }
        Err(e) => Err(Error::ScheduleStatus(e)),
    }
}
<commit_msg>Don't show ident for incomplete jobs<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Write;

use api_client;
use common::ui::{Status, UIWriter, UI};
use tabwriter::TabWriter;

use error::{Error, Result};
use {PRODUCT, VERSION};

pub fn start(
    ui: &mut UI,
    bldr_url: &str,
    group_id: Option<&str>,
    origin: Option<&str>,
    limit: usize,
    show_jobs: bool,
) -> Result<()> {
    let api_client =
        api_client::Client::new(bldr_url, PRODUCT, VERSION, None).map_err(Error::APIClient)?;

    if origin.is_some() {
        do_origin_status(ui, &api_client, origin.unwrap(), limit)?;
    } else {
        do_job_group_status(ui, &api_client, group_id.unwrap(), show_jobs)?;
    }

    Ok(())
}

fn do_job_group_status(
    ui: &mut UI,
    api_client: &api_client::Client,
    group_id: &str,
    show_jobs: bool,
) -> Result<()> {
    let gid = match group_id.parse::<i64>() {
        Ok(g) => g,
        Err(e) => {
            ui.fatal(format!("Failed to parse group id: {}", e))?;
            return Err(Error::ParseIntError(e));
        }
    };

    ui.status(
        Status::Determining,
        format!("status of job group {}", group_id),
    )?;

    match api_client.get_schedule(gid, show_jobs) {
        Ok(sr) => {
            let mut tw = TabWriter::new(vec![]);
            write!(&mut tw, "CREATED AT\tGROUP ID\tSTATUS\tIDENT\n").unwrap();
            write!(
                &mut tw,
                "{}\t{}\t{}\t{}\n",
                sr.created_at, sr.id, sr.state, sr.project_name,
            ).unwrap();
            tw.flush().unwrap();
            let mut written = String::from_utf8(tw.into_inner().unwrap()).unwrap();
            println!("\n{}", written);

            if show_jobs && !sr.projects.is_empty() {
                tw = TabWriter::new(vec![]);
                write!(&mut tw, "NAME\tSTATUS\tJOB ID\tIDENT\n").unwrap();
                for p in sr.projects {
                    // Don't show ident if the build did not succeed
                    // TODO: This will be fixed at the API level eventually
                    let ident = if p.state == "Success" { &p.ident } else { "" };
                    write!(
                        &mut tw,
                        "{}\t{}\t{}\t{}\n",
                        p.name, p.state, p.job_id, ident,
                    ).unwrap();
                }
                written = String::from_utf8(tw.into_inner().unwrap()).unwrap();
                println!("{}", written);
            }
            Ok(())
        }
        Err(e) => Err(Error::ScheduleStatus(e)),
    }
}

fn do_origin_status(
    ui: &mut UI,
    api_client: &api_client::Client,
    origin: &str,
    limit: usize,
) -> Result<()> {
    ui.status(
        Status::Determining,
        format!("status of job groups in {} origin", origin),
    )?;

    match api_client.get_origin_schedule(origin, limit) {
        Ok(sr) => {
            let mut tw = TabWriter::new(vec![]);
            write!(&mut tw, "CREATED AT\tGROUP ID\tSTATUS\tIDENT\n").unwrap();
            for s in sr.iter() {
                write!(
                    &mut tw,
                    "{}\t{}\t{}\t{}\n",
                    s.created_at, s.id, s.state, s.project_name,
                ).unwrap();
            }

            tw.flush().unwrap();
            let written = String::from_utf8(tw.into_inner().unwrap()).unwrap();
            println!("\n{}", written);
            Ok(())
        }
        Err(e) => Err(Error::ScheduleStatus(e)),
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::fs::File;
use std::io::{BufRead, BufReader, Read};

use img;
#[cfg(feature="openexr")]
use openexr::{FrameBufferMut, InputFile};

use {Point2i, clamp};
use bounds::Bounds2i;
use errors::*;
use fileutil::has_extension;
use spectrum::{Spectrum, gamma_correct};

pub fn read_image<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading image {}", path.as_ref().display());
    let path = path.as_ref();
    let extension = path.extension()
        .ok_or("Texture filename doesn't have an extension")?;
    if extension == "tga" || extension == "TGA" || extension == "png" || extension == "PNG" {
        read_image_tga_png(path)
    } else if extension == "exr" || extension == "EXR" {
        read_image_exr(path)
    } else if extension == "pfm" {
        read_image_pfm(path)
    } else if extension == "hdr" {
        read_image_hdr(path)
    } else {
        bail!("Unsupported file format");
    }
}

pub fn write_image<P: AsRef<Path>>(name: P, rgb: &[f32], output_bounds: &Bounds2i, total_resolution: &Point2i) -> Result<()> {
    let path = name.as_ref();
    let resolution = output_bounds.diagonal();

    if has_extension(path, "png") {
        let rgb8: Vec<_> = rgb.iter().map(|v| {
            clamp(255.0 * gamma_correct(*v) + 0.5, 0.0, 255.0) as u8
        }).collect();

        return img::save_buffer(path,
                         &rgb8,
                         resolution.x as u32,
                         resolution.y as u32,
                         img::RGB(8))
                .chain_err(|| format!("Failed to save image file {}", path.display()));
    } else {
        bail!("Unsupported file format");
    }
}

fn read_image_tga_png<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading texture {}", path.as_ref().display());
    let buf = img::open(path)?;

    let rgb = buf.to_rgb();
    let res = Point2i::new(rgb.width() as i32, rgb.height() as i32);
    let pixels: Vec<Spectrum> = rgb.pixels()
        .map(|p| {
                 let r = f32::from(p.data[0]) / 255.0;
                 let g = f32::from(p.data[1]) / 255.0;
                 let b = f32::from(p.data[2]) / 255.0;
                 Spectrum::rgb(r, g, b)
             })
        .collect();

    Ok((pixels, res))
}

fn read_image_hdr<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading HDR image {}", path.as_ref().display());
    let file = File::open(path.as_ref())?;
    let reader = BufReader::new(file);
    let hdr = img::hdr::HDRDecoder::new(reader)?;

    let meta = hdr.metadata();
    let data = hdr.read_image_transform(|p| {
        let rgb = p.to_hdr();
        Spectrum::rgb(rgb[0], rgb[1], rgb[2])
    })?;

    Ok((data, Point2i::new(meta.width as i32, meta.height as i32)))
}

#[cfg(not(feature="openexr"))]
fn read_image_exr<P: AsRef<Path>>(_path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    panic!("EXR support is not compiled in. Please recompile with the \"openexr\" feature.")
}

#[cfg(feature="openexr")]
fn read_image_exr<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading EXR texture {}", path.as_ref().display());
    let mut file = File::open(path.as_ref())?;
    let mut exr_file = InputFile::new(&mut file).unwrap();
    let (width, height) = {
        let window = exr_file.header().data_window();
        let width = window.max.x - window.min.x + 1;
        let height = window.max.y - window.min.y + 1;
        (width, height)
    };

    let mut pixel_data: Vec<(f32, f32, f32)> = vec![(0.0, 0.0, 0.0); (width * height) as usize];

    {
        let mut fb = {
            // Create the frame buffer
            let mut fb = FrameBufferMut::new(width as usize, height as usize);
            fb.insert_channels(&[("R", 0.0), ("G", 0.0), ("B", 0.0)], &mut pixel_data);
            fb
        };

        exr_file.read_pixels(&mut fb).unwrap();
    }

    let pixels = pixel_data
        .iter()
        .map(|&(r, g, b)| Spectrum::rgb(r, g, b))
        .collect();
    Ok((pixels, Point2i::new(width, height)))
}

fn is_whitespace(c: char) -> bool {
    c == ' ' || c == '\n' || c == '\t'
}

fn read_word<R: BufRead>(f: &mut R) -> String {
    let mut buf = String::new();
    for c in f.bytes() {
        let c = c.unwrap() as char;
        if is_whitespace(c) {
            break;
        }
        buf.push(c);
    }

    buf
}

fn read_image_pfm<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading PFM file {}", path.as_ref().display());
    let file = File::open(path.as_ref())?;
    let mut reader = BufReader::new(file);
    let mut word;

    word = read_word(&mut reader);
    let n_channels = if &word == "Pf" {
        1
    } else if &word == "PF" {
        3
    } else {
        bail!("Error reading PFM file \"{}\"", path.as_ref().display());
    };

    // Read the rest of the header
    // Read width
    word = read_word(&mut reader);
    let width: usize = word.parse().chain_err(|| "Failed to parse width")?;

    // Read height
    word = read_word(&mut reader);
    let height: usize = word.parse().chain_err(|| "Failed to parse height")?;

    // Read scale
    word = read_word(&mut reader);
    let scale: f32 = word.parse().chain_err(|| "Failed to parse scale")?;
    let file_little_endian = scale < 0.0;
    let host_little_endian = true;

    info!("n_channels={}, width={}, height={}, scale={}",
          n_channels,
          width,
          height,
          scale);

    // Read the rest of the data
    let n_floats = n_channels * width * height;
    let mut data = Vec::new();
    data.resize(n_floats, 0.0f32);
    // Flip in Y, as P*M has the origin at the lower left.
    for y in (0..height).rev() {
        for x in 0..width {
            for idx in 0..n_channels {
                let mut buf = [0u8; 4]; // buffer to read a float
                reader.read_exact(&mut buf)?;
                if host_little_endian ^ file_little_endian {
                    buf.as_mut().swap(0, 3);
                    buf.as_mut().swap(1, 2);
                }
                let mut float = unsafe { ::std::mem::transmute::<[u8; 4], f32>(buf) };
                if scale.abs() != 1.0 {
                    float *= scale.abs();
                }
                data[y * n_channels * width + x * n_channels + idx] = float;
            }
        }
    }

    let rgb: Vec<Spectrum> = if n_channels == 1 {
        data.iter().map(|v| Spectrum::from(*v)).collect()
    } else {
        data.chunks(3)
            .map(|rgb| Spectrum::rgb(rgb[0], rgb[1], rgb[2]))
            .collect()
    };

    Ok((rgb, Point2i::new(width as i32, height as i32)))
}
<commit_msg>Disable strict mode when loading HDR<commit_after>use std::path::Path;
use std::fs::File;
use std::io::{BufRead, BufReader, Read};

use img;
#[cfg(feature="openexr")]
use openexr::{FrameBufferMut, InputFile};

use {Point2i, clamp};
use bounds::Bounds2i;
use errors::*;
use fileutil::has_extension;
use spectrum::{Spectrum, gamma_correct};

pub fn read_image<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading image {}", path.as_ref().display());
    let path = path.as_ref();
    let extension = path.extension()
        .ok_or("Texture filename doesn't have an extension")?;
    if extension == "tga" || extension == "TGA" || extension == "png" || extension == "PNG" {
        read_image_tga_png(path)
    } else if extension == "exr" || extension == "EXR" {
        read_image_exr(path)
    } else if extension == "pfm" {
        read_image_pfm(path)
    } else if extension == "hdr" {
        read_image_hdr(path)
    } else {
        bail!("Unsupported file format");
    }
}

pub fn write_image<P: AsRef<Path>>(name: P, rgb: &[f32], output_bounds: &Bounds2i, total_resolution: &Point2i) -> Result<()> {
    let path = name.as_ref();
    let resolution = output_bounds.diagonal();

    if has_extension(path, "png") {
        let rgb8: Vec<_> = rgb.iter().map(|v| {
            clamp(255.0 * gamma_correct(*v) + 0.5, 0.0, 255.0) as u8
        }).collect();

        return img::save_buffer(path,
                         &rgb8,
                         resolution.x as u32,
                         resolution.y as u32,
                         img::RGB(8))
                .chain_err(|| format!("Failed to save image file {}", path.display()));
    } else {
        bail!("Unsupported file format");
    }
}

fn read_image_tga_png<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading texture {}", path.as_ref().display());
    let buf = img::open(path)?;

    let rgb = buf.to_rgb();
    let res = Point2i::new(rgb.width() as i32, rgb.height() as i32);
    let pixels: Vec<Spectrum> = rgb.pixels()
        .map(|p| {
                 let r = f32::from(p.data[0]) / 255.0;
                 let g = f32::from(p.data[1]) / 255.0;
                 let b = f32::from(p.data[2]) / 255.0;
                 Spectrum::rgb(r, g, b)
             })
        .collect();

    Ok((pixels, res))
}

fn read_image_hdr<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading HDR image {}", path.as_ref().display());
    let file = File::open(path.as_ref())?;
    let reader = BufReader::new(file);
    let hdr = img::hdr::HDRDecoder::with_strictness(reader, false)?;

    let meta = hdr.metadata();
    let data = hdr.read_image_transform(|p| {
        let rgb = p.to_hdr();
        Spectrum::rgb(rgb[0], rgb[1], rgb[2])
    })?;

    Ok((data, Point2i::new(meta.width as i32, meta.height as i32)))
}

#[cfg(not(feature="openexr"))]
fn read_image_exr<P: AsRef<Path>>(_path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    panic!("EXR support is not compiled in. Please recompile with the \"openexr\" feature.")
}

#[cfg(feature="openexr")]
fn read_image_exr<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading EXR texture {}", path.as_ref().display());
    let mut file = File::open(path.as_ref())?;
    let mut exr_file = InputFile::new(&mut file).unwrap();
    let (width, height) = {
        let window = exr_file.header().data_window();
        let width = window.max.x - window.min.x + 1;
        let height = window.max.y - window.min.y + 1;
        (width, height)
    };

    let mut pixel_data: Vec<(f32, f32, f32)> = vec![(0.0, 0.0, 0.0); (width * height) as usize];

    {
        let mut fb = {
            // Create the frame buffer
            let mut fb = FrameBufferMut::new(width as usize, height as usize);
            fb.insert_channels(&[("R", 0.0), ("G", 0.0), ("B", 0.0)], &mut pixel_data);
            fb
        };

        exr_file.read_pixels(&mut fb).unwrap();
    }

    let pixels = pixel_data
        .iter()
        .map(|&(r, g, b)| Spectrum::rgb(r, g, b))
        .collect();
    Ok((pixels, Point2i::new(width, height)))
}

fn is_whitespace(c: char) -> bool {
    c == ' ' || c == '\n' || c == '\t'
}

fn read_word<R: BufRead>(f: &mut R) -> String {
    let mut buf = String::new();
    for c in f.bytes() {
        let c = c.unwrap() as char;
        if is_whitespace(c) {
            break;
        }
        buf.push(c);
    }

    buf
}

fn read_image_pfm<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading PFM file {}", path.as_ref().display());
    let file = File::open(path.as_ref())?;
    let mut reader = BufReader::new(file);
    let mut word;

    word = read_word(&mut reader);
    let n_channels = if &word == "Pf" {
        1
    } else if &word == "PF" {
        3
    } else {
        bail!("Error reading PFM file \"{}\"", path.as_ref().display());
    };

    // Read the rest of the header
    // Read width
    word = read_word(&mut reader);
    let width: usize = word.parse().chain_err(|| "Failed to parse width")?;

    // Read height
    word = read_word(&mut reader);
    let height: usize = word.parse().chain_err(|| "Failed to parse height")?;

    // Read scale
    word = read_word(&mut reader);
    let scale: f32 = word.parse().chain_err(|| "Failed to parse scale")?;
    let file_little_endian = scale < 0.0;
    let host_little_endian = true;

    info!("n_channels={}, width={}, height={}, scale={}",
          n_channels,
          width,
          height,
          scale);

    // Read the rest of the data
    let n_floats = n_channels * width * height;
    let mut data = Vec::new();
    data.resize(n_floats, 0.0f32);
    // Flip in Y, as P*M has the origin at the lower left.
    for y in (0..height).rev() {
        for x in 0..width {
            for idx in 0..n_channels {
                let mut buf = [0u8; 4]; // buffer to read a float
                reader.read_exact(&mut buf)?;
                if host_little_endian ^ file_little_endian {
                    buf.as_mut().swap(0, 3);
                    buf.as_mut().swap(1, 2);
                }
                let mut float = unsafe { ::std::mem::transmute::<[u8; 4], f32>(buf) };
                if scale.abs() != 1.0 {
                    float *= scale.abs();
                }
                data[y * n_channels * width + x * n_channels + idx] = float;
            }
        }
    }

    let rgb: Vec<Spectrum> = if n_channels == 1 {
        data.iter().map(|v| Spectrum::from(*v)).collect()
    } else {
        data.chunks(3)
            .map(|rgb| Spectrum::rgb(rgb[0], rgb[1], rgb[2]))
            .collect()
    };

    Ok((rgb, Point2i::new(width as i32, height as i32)))
}
<|endoftext|>


<commit_before>use amq_protocol::frame::{GenError, Offset, gen_frame, parse_frame};
use log::{error, trace};
use mio::{Evented, Events, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
use parking_lot::Mutex;

use std::{
  io::{self, Read, Write},
  sync::{
    Arc,
    atomic::{AtomicBool, Ordering},
  },
  thread::{self, Builder as ThreadBuilder, JoinHandle},
  time::{Duration, Instant},
};

use crate::{
  buffer::Buffer,
  connection::Connection,
  connection_status::ConnectionState,
  error::{Error, ErrorKind},
};

const SOCKET:   Token = Token(1);
const DATA:     Token = Token(2);
const CONTINUE: Token = Token(3);

const FRAMES_STORAGE: usize = 32;

#[derive(Clone, Debug)]
pub(crate) struct IoLoopHandle {
  handle: Arc<Mutex<Option<JoinHandle<Result<(), Error>>>>>,
}

impl Default for IoLoopHandle {
  fn default() -> Self {
    Self { handle: Arc::new(Mutex::new(None)) }
  }
}

impl IoLoopHandle {
  pub(crate) fn register(&self, handle: JoinHandle<Result<(), Error>>) {
    *self.handle.lock() = Some(handle);
  }

  pub(crate) fn wait(&self) -> Result<(), Error> {
    if let Some(handle) = self.handle.lock().take() {
      handle.join().expect("io loop")?
    }
    Ok(())
  }
}

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

pub(crate) struct IoLoop<T> {
  connection:     Connection,
  socket:         T,
  status:         Status,
  poll:           Poll,
  registration:   Registration,
  set_readiness:  SetReadiness,
  hb_handle:      Option<JoinHandle<()>>,
  frame_size:     usize,
  receive_buffer: Buffer,
  send_buffer:    Buffer,
  can_write:      bool,
  can_read:       bool,
  has_data:       bool,
  send_heartbeat: Arc<AtomicBool>,
  poll_timeout:   Option<Duration>,
}

impl<T: Evented + Read + Write + Send + 'static> IoLoop<T> {
  pub(crate) fn new(connection: Connection, socket: T) -> Result<Self, Error> {
    let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
    let (registration, set_readiness) = Registration::new2();
    let inner = Self {
      connection,
      socket,
      status:         Status::Initial,
      poll:           Poll::new().map_err(ErrorKind::IOError)?,
      registration,
      set_readiness,
      hb_handle:      None,
      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,
      has_data:       false,
      send_heartbeat: Arc::new(AtomicBool::new(false)),
      poll_timeout:   None,
    };
    inner.poll.register(&inner.socket, SOCKET, Ready::all(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    inner.poll.register(&inner.connection, DATA, Ready::readable(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    inner.poll.register(&inner.registration, CONTINUE, Ready::readable(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    Ok(inner)
  }

  fn start_heartbeat(&mut self, interval: Duration) -> Result<(), Error> {
    let connection    = self.connection.clone();
    let send_hartbeat = self.send_heartbeat.clone();
    let hb_handle = ThreadBuilder::new().name("heartbeat".to_owned()).spawn(move || {
      while connection.status().connected() {
        let start         = Instant::now();
        let mut remaining = interval;

        loop {
          thread::park_timeout(remaining);
          let elapsed = start.elapsed();
          if elapsed >= remaining {
            break
          }
          remaining -= interval - elapsed;
        }

        send_hartbeat.store(true, Ordering::Relaxed);
      }
    }).map_err(ErrorKind::IOError)?;
    self.hb_handle = Some(hb_handle);
    Ok(())
  }

  fn heartbeat(&mut self) -> Result<(), Error> {
    trace!("send heartbeat");
    self.connection.send_heartbeat()?;
    self.send_heartbeat.store(false, Ordering::Relaxed);
    Ok(())
  }

  fn ensure_setup(&mut self) -> Result<(), Error> {
    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 {
        trace!("io_loop: start heartbeat");
        let heartbeat = Duration::from_secs(heartbeat as u64);
        self.start_heartbeat(heartbeat)?;
        self.poll_timeout = Some(heartbeat);
        trace!("io_loop: heartbeat started");
      }
      self.status = Status::Setup;
    }
    Ok(())
  }

  fn wants_to_write(&self) -> bool {
    self.can_write && self.has_data
  }

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

  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 run(mut self) -> Result<(), Error> {
    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() {
        self.do_run(&mut events)?;
      }
      if let Some(hb_handle) = self.hb_handle.take() {
        hb_handle.thread().unpark();
        hb_handle.join().expect("heartbeat loop failed");
      }
      Ok(())
    }).map_err(ErrorKind::IOError)?);
    Ok(())
  }

  fn do_run(&mut self, events: &mut Events) -> Result<(), Error> {
    // First, update our internal state
    trace!("io_loop run");
    self.ensure_setup()?;
    trace!("io_loop poll");
    self.poll.poll(events, self.poll_timeout).map_err(ErrorKind::IOError)?;
    trace!("io_loop poll done");
    for event in events.iter() {
      match event.token() {
        SOCKET    => {
          if event.readiness().is_readable() {
            self.can_read = true;
          }
          if event.readiness().is_writable() {
            self.can_write = true;
          }
        },
        DATA      => self.has_data = true,
        _         => {},
      }
    }

    // Then, actually run an iteration of the event loop
    trace!("io_loop do_run; can_read={}, can_write={}, has_data={}", self.can_read, self.can_write, self.has_data);
    loop {
      if self.send_heartbeat.load(Ordering::Relaxed) {
        self.heartbeat()?;
      }
      if self.wants_to_write() && !self.connection.status().blocked() {
        if let Err(e) = self.write_to_stream() {
          match e.kind() {
            ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock => self.can_write = false,
            _ => {
              error!("error writing: {:?}", e);
              if let ConnectionState::SentProtocolHeader(wait_handle, ..) = self.connection.status().state() {
                wait_handle.error(ErrorKind::ConnectionRefused.into());
                self.status = Status::Stop;
              }
              self.connection.set_error()?;
              return Err(e);
            }
          }
        }
        self.send_buffer.shift_unless_available(self.frame_size);
      }
      if self.connection.status().closed() {
        self.status = Status::Stop;
      }
      if self.should_continue() && self.wants_to_read() {
        if let Err(e) = self.read_from_stream() {
          match e.kind() {
            ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock => self.can_read = false,
            _ => {
              error!("error reading: {:?}", e);
              self.connection.set_error()?;
              return Err(e);
            }
          }
        }
        self.receive_buffer.shift_unless_available(self.frame_size);
      }
      if self.can_parse() {
        self.parse()?;
      }
      if !self.wants_to_read() || !self.wants_to_write() || self.status == Status::Stop || self.connection.status().errored() {
        if self.status != Status::Stop && (self.wants_to_read() || self.can_parse() || self.has_data) {
          trace!("io_loop send continue; can_read={}, can_write={}, has_data={}", self.can_read, self.can_write, self.has_data);
          self.set_readiness.set_readiness(Ready::readable()).map_err(ErrorKind::IOError)?;
        }
        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 can_parse(&self) -> bool {
    self.receive_buffer.available_data() > 0
  }

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

    self.socket.write(&self.send_buffer.data()).map(|sz| {
      trace!("wrote {} bytes", sz);
      self.send_buffer.consume(sz);
    }).map_err(|e| ErrorKind::IOError(e).into())
  }

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

  fn serialize(&mut self) -> Result<(), Error> {
    if let Some((send_id, next_msg)) = self.connection.next_frame() {
      trace!("will write to buffer: {:?}", next_msg);
      match gen_frame(self.send_buffer.space(), &next_msg).map(|tup| tup.0) {
        Ok(sz) => {
          self.send_buffer.fill(sz);
          self.connection.mark_sent(send_id);
          Ok(())
        },
        Err(e) => {
          match e {
            GenError::BufferTooSmall(_) => {
              // Requeue msg
              self.connection.requeue_frame(send_id, next_msg)?;
              self.send_buffer.shift();
              Ok(())
            },
            GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
              error!("error generating frame: {:?}", e);
              self.connection.set_error()?;
              Err(ErrorKind::SerialisationError(e).into())
            }
          }
        }
      }
    } else {
      self.has_data = false;
      Ok(())
    }
  }

  fn parse(&mut self) -> Result<(), Error> {
    match parse_frame(self.receive_buffer.data()) {
      Ok((i, f)) => {
        let consumed = self.receive_buffer.data().offset(i);
        self.receive_buffer.consume(consumed);

        if let Err(e) = self.connection.handle_frame(f) {
          self.connection.set_error()?;
          Err(e)
        } else {
          Ok(())
        }
      },
      Err(e) => {
        if e.is_incomplete() {
          self.receive_buffer.shift();
          Ok(())
        } else {
          error!("parse error: {:?}", e);
          self.connection.set_error()?;
          Err(ErrorKind::ParsingError(format!("{:?}", e)).into())
        }
      }
    }
  }
}
<commit_msg>make IoLoop public<commit_after>use amq_protocol::frame::{GenError, Offset, gen_frame, parse_frame};
use log::{error, trace};
use mio::{Evented, Events, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
use parking_lot::Mutex;

use std::{
  io::{self, Read, Write},
  sync::{
    Arc,
    atomic::{AtomicBool, Ordering},
  },
  thread::{self, Builder as ThreadBuilder, JoinHandle},
  time::{Duration, Instant},
};

use crate::{
  buffer::Buffer,
  connection::Connection,
  connection_status::ConnectionState,
  error::{Error, ErrorKind},
};

const SOCKET:   Token = Token(1);
const DATA:     Token = Token(2);
const CONTINUE: Token = Token(3);

const FRAMES_STORAGE: usize = 32;

#[derive(Clone, Debug)]
pub(crate) struct IoLoopHandle {
  handle: Arc<Mutex<Option<JoinHandle<Result<(), Error>>>>>,
}

impl Default for IoLoopHandle {
  fn default() -> Self {
    Self { handle: Arc::new(Mutex::new(None)) }
  }
}

impl IoLoopHandle {
  pub(crate) fn register(&self, handle: JoinHandle<Result<(), Error>>) {
    *self.handle.lock() = Some(handle);
  }

  pub(crate) fn wait(&self) -> Result<(), Error> {
    if let Some(handle) = self.handle.lock().take() {
      handle.join().expect("io loop")?
    }
    Ok(())
  }
}

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

pub struct IoLoop<T> {
  connection:     Connection,
  socket:         T,
  status:         Status,
  poll:           Poll,
  registration:   Registration,
  set_readiness:  SetReadiness,
  hb_handle:      Option<JoinHandle<()>>,
  frame_size:     usize,
  receive_buffer: Buffer,
  send_buffer:    Buffer,
  can_write:      bool,
  can_read:       bool,
  has_data:       bool,
  send_heartbeat: Arc<AtomicBool>,
  poll_timeout:   Option<Duration>,
}

impl<T: Evented + Read + Write + Send + 'static> IoLoop<T> {
  pub(crate) fn new(connection: Connection, socket: T) -> Result<Self, Error> {
    let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
    let (registration, set_readiness) = Registration::new2();
    let inner = Self {
      connection,
      socket,
      status:         Status::Initial,
      poll:           Poll::new().map_err(ErrorKind::IOError)?,
      registration,
      set_readiness,
      hb_handle:      None,
      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,
      has_data:       false,
      send_heartbeat: Arc::new(AtomicBool::new(false)),
      poll_timeout:   None,
    };
    inner.poll.register(&inner.socket, SOCKET, Ready::all(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    inner.poll.register(&inner.connection, DATA, Ready::readable(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    inner.poll.register(&inner.registration, CONTINUE, Ready::readable(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    Ok(inner)
  }

  fn start_heartbeat(&mut self, interval: Duration) -> Result<(), Error> {
    let connection    = self.connection.clone();
    let send_hartbeat = self.send_heartbeat.clone();
    let hb_handle = ThreadBuilder::new().name("heartbeat".to_owned()).spawn(move || {
      while connection.status().connected() {
        let start         = Instant::now();
        let mut remaining = interval;

        loop {
          thread::park_timeout(remaining);
          let elapsed = start.elapsed();
          if elapsed >= remaining {
            break
          }
          remaining -= interval - elapsed;
        }

        send_hartbeat.store(true, Ordering::Relaxed);
      }
    }).map_err(ErrorKind::IOError)?;
    self.hb_handle = Some(hb_handle);
    Ok(())
  }

  fn heartbeat(&mut self) -> Result<(), Error> {
    trace!("send heartbeat");
    self.connection.send_heartbeat()?;
    self.send_heartbeat.store(false, Ordering::Relaxed);
    Ok(())
  }

  fn ensure_setup(&mut self) -> Result<(), Error> {
    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 {
        trace!("io_loop: start heartbeat");
        let heartbeat = Duration::from_secs(heartbeat as u64);
        self.start_heartbeat(heartbeat)?;
        self.poll_timeout = Some(heartbeat);
        trace!("io_loop: heartbeat started");
      }
      self.status = Status::Setup;
    }
    Ok(())
  }

  fn wants_to_write(&self) -> bool {
    self.can_write && self.has_data
  }

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

  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 run(mut self) -> Result<(), Error> {
    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() {
        self.do_run(&mut events)?;
      }
      if let Some(hb_handle) = self.hb_handle.take() {
        hb_handle.thread().unpark();
        hb_handle.join().expect("heartbeat loop failed");
      }
      Ok(())
    }).map_err(ErrorKind::IOError)?);
    Ok(())
  }

  fn do_run(&mut self, events: &mut Events) -> Result<(), Error> {
    // First, update our internal state
    trace!("io_loop run");
    self.ensure_setup()?;
    trace!("io_loop poll");
    self.poll.poll(events, self.poll_timeout).map_err(ErrorKind::IOError)?;
    trace!("io_loop poll done");
    for event in events.iter() {
      match event.token() {
        SOCKET    => {
          if event.readiness().is_readable() {
            self.can_read = true;
          }
          if event.readiness().is_writable() {
            self.can_write = true;
          }
        },
        DATA      => self.has_data = true,
        _         => {},
      }
    }

    // Then, actually run an iteration of the event loop
    trace!("io_loop do_run; can_read={}, can_write={}, has_data={}", self.can_read, self.can_write, self.has_data);
    loop {
      if self.send_heartbeat.load(Ordering::Relaxed) {
        self.heartbeat()?;
      }
      if self.wants_to_write() && !self.connection.status().blocked() {
        if let Err(e) = self.write_to_stream() {
          match e.kind() {
            ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock => self.can_write = false,
            _ => {
              error!("error writing: {:?}", e);
              if let ConnectionState::SentProtocolHeader(wait_handle, ..) = self.connection.status().state() {
                wait_handle.error(ErrorKind::ConnectionRefused.into());
                self.status = Status::Stop;
              }
              self.connection.set_error()?;
              return Err(e);
            }
          }
        }
        self.send_buffer.shift_unless_available(self.frame_size);
      }
      if self.connection.status().closed() {
        self.status = Status::Stop;
      }
      if self.should_continue() && self.wants_to_read() {
        if let Err(e) = self.read_from_stream() {
          match e.kind() {
            ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock => self.can_read = false,
            _ => {
              error!("error reading: {:?}", e);
              self.connection.set_error()?;
              return Err(e);
            }
          }
        }
        self.receive_buffer.shift_unless_available(self.frame_size);
      }
      if self.can_parse() {
        self.parse()?;
      }
      if !self.wants_to_read() || !self.wants_to_write() || self.status == Status::Stop || self.connection.status().errored() {
        if self.status != Status::Stop && (self.wants_to_read() || self.can_parse() || self.has_data) {
          trace!("io_loop send continue; can_read={}, can_write={}, has_data={}", self.can_read, self.can_write, self.has_data);
          self.set_readiness.set_readiness(Ready::readable()).map_err(ErrorKind::IOError)?;
        }
        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 can_parse(&self) -> bool {
    self.receive_buffer.available_data() > 0
  }

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

    self.socket.write(&self.send_buffer.data()).map(|sz| {
      trace!("wrote {} bytes", sz);
      self.send_buffer.consume(sz);
    }).map_err(|e| ErrorKind::IOError(e).into())
  }

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

  fn serialize(&mut self) -> Result<(), Error> {
    if let Some((send_id, next_msg)) = self.connection.next_frame() {
      trace!("will write to buffer: {:?}", next_msg);
      match gen_frame(self.send_buffer.space(), &next_msg).map(|tup| tup.0) {
        Ok(sz) => {
          self.send_buffer.fill(sz);
          self.connection.mark_sent(send_id);
          Ok(())
        },
        Err(e) => {
          match e {
            GenError::BufferTooSmall(_) => {
              // Requeue msg
              self.connection.requeue_frame(send_id, next_msg)?;
              self.send_buffer.shift();
              Ok(())
            },
            GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
              error!("error generating frame: {:?}", e);
              self.connection.set_error()?;
              Err(ErrorKind::SerialisationError(e).into())
            }
          }
        }
      }
    } else {
      self.has_data = false;
      Ok(())
    }
  }

  fn parse(&mut self) -> Result<(), Error> {
    match parse_frame(self.receive_buffer.data()) {
      Ok((i, f)) => {
        let consumed = self.receive_buffer.data().offset(i);
        self.receive_buffer.consume(consumed);

        if let Err(e) = self.connection.handle_frame(f) {
          self.connection.set_error()?;
          Err(e)
        } else {
          Ok(())
        }
      },
      Err(e) => {
        if e.is_incomplete() {
          self.receive_buffer.shift();
          Ok(())
        } else {
          error!("parse error: {:?}", e);
          self.connection.set_error()?;
          Err(ErrorKind::ParsingError(format!("{:?}", e)).into())
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>use super::command::{Help, HelpOptions, HelpFunction};
pub use super::{Args, CommandGroup, CommandOptions, CommandError, HelpBehaviour};

use utils::Colour;
use std::fmt::Write;
use std::sync::Arc;

pub struct CreateHelpCommand(pub HelpOptions, pub HelpFunction);

impl CreateHelpCommand {

    /// Sets a message displaying if input could not be found
    /// but a similar command is available.
    ///
    /// **Note**: `{}` will be substituted with the actual suggested command-name.
    /// Hence no `{}` results in no command-name.
    pub fn suggestion_text(mut self, text: &str) -> Self {
        self.0.suggestion_text = text.to_string();

        self
    }

    /// Sets a message displaying if there is no help available.
    pub fn no_help_available_text(mut self, text: &str) -> Self {
        self.0.no_help_available_text = text.to_string();

        self
    }

    /// Sets a label for usage of a command.
    pub fn usage_label(mut self, text: &str) -> Self {
        self.0.usage_label = text.to_string();

        self
    }

    /// Sets a label for the usage examples of a command.
    pub fn usage_sample_label(mut self, text: &str) -> Self {
        self.0.usage_sample_label = text.to_string();

        self
    }

    /// Sets a label for ungrouped-commands
    pub fn ungrouped_label(mut self, text: &str) -> Self {
        self.0.ungrouped_label = text.to_string();

        self
    }

    /// Sets a label for grouped-commands.
    pub fn grouped_label(mut self, text: &str) -> Self {
        self.0.grouped_label = text.to_string();

        self
    }

    /// Sets a label for aliases.
    pub fn aliases_label(mut self, text: &str) -> Self {
        self.0.aliases_label = text.to_string();

        self
    }

    /// Sets a message displaying if a command is only available
    /// in guilds.
    pub fn guild_only_text(mut self, text: &str) -> Self {
        self.0.guild_only_text = text.to_string();

        self
    }

    /// Sets a message displaying if a command is only available
    /// in direct messages (DMs);
    pub fn dm_only_text(mut self, text: &str) -> Self {
        self.0.dm_only_text = text.to_string();

        self
    }

    /// Sets a message displaying if a command is available in
    /// guilds and DMs.
    pub fn dm_and_guilds_text(mut self, text: &str) -> Self {
        self.0.dm_and_guild_text = text.to_string();

        self
    }

    /// Sets a message displaying if a command is available to use.
    pub fn available_text(mut self, text: &str) -> Self {
        self.0.available_text = text.to_string();

        self
    }

    /// Sets a message that will appear upon failing to find
    /// an individual command.
    /// As in: `{prefix}help {command_name}`, but a command or
    /// alias like `{command_name}` does not exist.
    ///
    /// **Note**: `{}` will be substituted with the actual suggested command-name.
    /// Hence no `{}` results in no command-name.
    pub fn command_not_found_text(mut self, text: &str) -> Self {
        self.0.command_not_found_text = text.to_string();

        self
    }

    /// Sets the message on top of the help-menu, informing the
    /// user how to obtain more information about a single command.
    pub fn individual_command_tip(mut self, text: &str) -> Self {
        self.0.individual_command_tip = text.to_string();

        self
    }

    /// Sets how the group-prexix shall be labeled.
    pub fn group_prefix(mut self, text: &str) -> Self {
        self.0.group_prefix = text.to_string();

        self
    }

    /// Sets how a command requiring roles, that a user is lacking,
    /// shall appear in the help-menu.
    pub fn lacking_role(mut self, behaviour: HelpBehaviour) -> Self {
        self.0.lacking_role = behaviour;

        self
    }

    /// Sets how a command requiring permission, that a user is lacking,
    /// shall be appear in the help-menu.
    pub fn lacking_permissions(mut self, behaviour: HelpBehaviour) -> Self {
        self.0.lacking_permissions = behaviour;

        self
    }

    /// Sets how a command requiring to be sent in either via DM
    /// or a guild should be treated in the help-menu.
    pub fn wrong_channel(mut self, behaviour: HelpBehaviour) -> Self {
        self.0.wrong_channel = behaviour;

        self
    }

    /// Sets the tip (or legend) explaining why some commands are striked.
    /// By default this is `Some(String)` and the `String` is empty resulting
    /// in an automated substitution based on your `HelpBehaviour`-settings.
    /// If set to `None`, no tip will be given nor will it be substituted.
    /// If set to a non-empty `Some(String)`, the `String` will be displayed as tip.
    pub fn striked_commands_tip(mut self, text: Option<String>) -> Self {
        self.0.striked_commands_tip = text;

        self
    }

    /// Sets the colour for the embed if an error occured.
    pub fn embed_success_colour(mut self, colour: Colour) -> Self {
        self.0.embed_success_colour = colour;

        self
    }

    /// Sets the colour for the embed if no error occured.
    pub fn embed_error_colour(mut self, colour: Colour) -> Self {
        self.0.embed_error_colour = colour;

        self
    }

    /// Finishes the creation of a help-command, returning `Help`.
    /// If `Some(String)` was set as `striked_commands_tip` and the `String` is empty,
    /// the creator will substitute content based on the `HelpBehaviour`-settings.
    pub(crate) fn finish(self) -> Arc<Help> {
        if self.0.striked_commands_tip == Some(String::new()) {
            let mut strike_text = String::from("~~`Striked commands`~~ are unavailable because they");
            let mut concat_with_comma = false;

            if self.0.lacking_permissions == HelpBehaviour::Strike {
                let _ = write!(strike_text, "require permissions");
                concat_with_comma = true;
            }

            if self.0.lacking_role == HelpBehaviour::Strike {

                if concat_with_comma {
                    let _ = write!(strike_text, ", require a specific role");
                } else {
                    let _ = write!(strike_text, " require a specific role");
                    concat_with_comma = true;
                }
            }

            if self.0.wrong_channel == HelpBehaviour::Strike {

                if concat_with_comma {
                    let _ = write!(strike_text, " and are limited to DM/guilds");
                } else {
                    let _ = write!(strike_text, " are limited to DM/guilds");
                }
            }

            let _ = write!(strike_text, ".");
            let CreateHelpCommand(options, function) = self.striked_commands_tip(Some(strike_text));
            return Arc::new(Help(function, Arc::new(options)))
        }
        let CreateHelpCommand(options, function) = self;

        Arc::new(Help(function, Arc::new(options)))
    }
}<commit_msg>Fix whitespacing and change `and` to `or`. (#228)<commit_after>use super::command::{Help, HelpOptions, HelpFunction};
pub use super::{Args, CommandGroup, CommandOptions, CommandError, HelpBehaviour};

use utils::Colour;
use std::fmt::Write;
use std::sync::Arc;

pub struct CreateHelpCommand(pub HelpOptions, pub HelpFunction);

impl CreateHelpCommand {

    /// Sets a message displaying if input could not be found
    /// but a similar command is available.
    ///
    /// **Note**: `{}` will be substituted with the actual suggested command-name.
    /// Hence no `{}` results in no command-name.
    pub fn suggestion_text(mut self, text: &str) -> Self {
        self.0.suggestion_text = text.to_string();

        self
    }

    /// Sets a message displaying if there is no help available.
    pub fn no_help_available_text(mut self, text: &str) -> Self {
        self.0.no_help_available_text = text.to_string();

        self
    }

    /// Sets a label for usage of a command.
    pub fn usage_label(mut self, text: &str) -> Self {
        self.0.usage_label = text.to_string();

        self
    }

    /// Sets a label for the usage examples of a command.
    pub fn usage_sample_label(mut self, text: &str) -> Self {
        self.0.usage_sample_label = text.to_string();

        self
    }

    /// Sets a label for ungrouped-commands
    pub fn ungrouped_label(mut self, text: &str) -> Self {
        self.0.ungrouped_label = text.to_string();

        self
    }

    /// Sets a label for grouped-commands.
    pub fn grouped_label(mut self, text: &str) -> Self {
        self.0.grouped_label = text.to_string();

        self
    }

    /// Sets a label for aliases.
    pub fn aliases_label(mut self, text: &str) -> Self {
        self.0.aliases_label = text.to_string();

        self
    }

    /// Sets a message displaying if a command is only available
    /// in guilds.
    pub fn guild_only_text(mut self, text: &str) -> Self {
        self.0.guild_only_text = text.to_string();

        self
    }

    /// Sets a message displaying if a command is only available
    /// in direct messages (DMs);
    pub fn dm_only_text(mut self, text: &str) -> Self {
        self.0.dm_only_text = text.to_string();

        self
    }

    /// Sets a message displaying if a command is available in
    /// guilds and DMs.
    pub fn dm_and_guilds_text(mut self, text: &str) -> Self {
        self.0.dm_and_guild_text = text.to_string();

        self
    }

    /// Sets a message displaying if a command is available to use.
    pub fn available_text(mut self, text: &str) -> Self {
        self.0.available_text = text.to_string();

        self
    }

    /// Sets a message that will appear upon failing to find
    /// an individual command.
    /// As in: `{prefix}help {command_name}`, but a command or
    /// alias like `{command_name}` does not exist.
    ///
    /// **Note**: `{}` will be substituted with the actual suggested command-name.
    /// Hence no `{}` results in no command-name.
    pub fn command_not_found_text(mut self, text: &str) -> Self {
        self.0.command_not_found_text = text.to_string();

        self
    }

    /// Sets the message on top of the help-menu, informing the
    /// user how to obtain more information about a single command.
    pub fn individual_command_tip(mut self, text: &str) -> Self {
        self.0.individual_command_tip = text.to_string();

        self
    }

    /// Sets how the group-prexix shall be labeled.
    pub fn group_prefix(mut self, text: &str) -> Self {
        self.0.group_prefix = text.to_string();

        self
    }

    /// Sets how a command requiring roles, that a user is lacking,
    /// shall appear in the help-menu.
    pub fn lacking_role(mut self, behaviour: HelpBehaviour) -> Self {
        self.0.lacking_role = behaviour;

        self
    }

    /// Sets how a command requiring permission, that a user is lacking,
    /// shall be appear in the help-menu.
    pub fn lacking_permissions(mut self, behaviour: HelpBehaviour) -> Self {
        self.0.lacking_permissions = behaviour;

        self
    }

    /// Sets how a command requiring to be sent in either via DM
    /// or a guild should be treated in the help-menu.
    pub fn wrong_channel(mut self, behaviour: HelpBehaviour) -> Self {
        self.0.wrong_channel = behaviour;

        self
    }

    /// Sets the tip (or legend) explaining why some commands are striked.
    /// By default this is `Some(String)` and the `String` is empty resulting
    /// in an automated substitution based on your `HelpBehaviour`-settings.
    /// If set to `None`, no tip will be given nor will it be substituted.
    /// If set to a non-empty `Some(String)`, the `String` will be displayed as tip.
    pub fn striked_commands_tip(mut self, text: Option<String>) -> Self {
        self.0.striked_commands_tip = text;

        self
    }

    /// Sets the colour for the embed if an error occured.
    pub fn embed_success_colour(mut self, colour: Colour) -> Self {
        self.0.embed_success_colour = colour;

        self
    }

    /// Sets the colour for the embed if no error occured.
    pub fn embed_error_colour(mut self, colour: Colour) -> Self {
        self.0.embed_error_colour = colour;

        self
    }

    /// Finishes the creation of a help-command, returning `Help`.
    /// If `Some(String)` was set as `striked_commands_tip` and the `String` is empty,
    /// the creator will substitute content based on the `HelpBehaviour`-settings.
    pub(crate) fn finish(self) -> Arc<Help> {
        if self.0.striked_commands_tip == Some(String::new()) {
            let mut strike_text = String::from("~~`Striked commands`~~ are unavailable because they");
            let mut concat_with_comma = false;

            if self.0.lacking_permissions == HelpBehaviour::Strike {
                let _ = write!(strike_text, " require permissions");
                concat_with_comma = true;
            }

            if self.0.lacking_role == HelpBehaviour::Strike {

                if concat_with_comma {
                    let _ = write!(strike_text, ", require a specific role");
                } else {
                    let _ = write!(strike_text, " require a specific role");
                    concat_with_comma = true;
                }
            }

            if self.0.wrong_channel == HelpBehaviour::Strike {

                if concat_with_comma {
                    let _ = write!(strike_text, " or are limited to DM/guilds");
                } else {
                    let _ = write!(strike_text, " are limited to DM/guilds");
                }
            }

            let _ = write!(strike_text, ".");
            let CreateHelpCommand(options, function) = self.striked_commands_tip(Some(strike_text));
            return Arc::new(Help(function, Arc::new(options)))
        }
        let CreateHelpCommand(options, function) = self;

        Arc::new(Help(function, Arc::new(options)))
    }
}<|endoftext|>


<commit_before>//! Loggers and logging events for differential dataflow.

/// Logger for differential dataflow events.
pub type Logger = ::timely::logging::Logger<DifferentialEvent>;

/// Enables logging of differential dataflow events.
pub fn enable<A, W>(worker: &mut timely::worker::Worker<A>, writer: W) -> Option<Box<std::any::Any+'static>>
where
    A: timely::communication::Allocate,
    W: std::io::Write+'static,
{
    let writer = ::timely::dataflow::operators::capture::EventWriter::new(writer);
    let mut logger = ::timely::logging::BatchLogger::new(writer);
    worker
        .log_register()
        .insert::<DifferentialEvent,_>("differential/arrange", move |time, data| logger.publish_batch(time, data))
}

/// Possible different differential events.
#[derive(Debug, Clone, Abomonation, Ord, PartialOrd, Eq, PartialEq)]
pub enum DifferentialEvent {
    /// Batch creation.
    Batch(BatchEvent),
    /// Merge start and stop events.
    Merge(MergeEvent),
    /// Batch dropped when trace dropped.
    Drop(DropEvent),
    /// A merge failed to complete in time.
    MergeShortfall(MergeShortfall),
}

/// Either the start or end of a merge event.
#[derive(Debug, Clone, Abomonation, Ord, PartialOrd, Eq, PartialEq)]
pub struct BatchEvent {
    /// Operator identifier.
    pub operator: usize,
    /// Which order of magnitude.
    pub length: usize,
}

impl From<BatchEvent> for DifferentialEvent { fn from(e: BatchEvent) -> Self { DifferentialEvent::Batch(e) } }

/// Either the start or end of a merge event.
#[derive(Debug, Clone, Abomonation, Ord, PartialOrd, Eq, PartialEq)]
pub struct DropEvent {
    /// Operator identifier.
    pub operator: usize,
    /// Which order of magnitude.
    pub length: usize,
}

impl From<DropEvent> for DifferentialEvent { fn from(e: DropEvent) -> Self { DifferentialEvent::Drop(e) } }

/// Either the start or end of a merge event.
#[derive(Debug, Clone, Abomonation, Ord, PartialOrd, Eq, PartialEq)]
pub struct MergeEvent {
    /// Operator identifier.
    pub operator: usize,
    /// Which order of magnitude.
    pub scale: usize,
    /// Length of first trace.
    pub length1: usize,
    /// Length of second trace.
    pub length2: usize,
    /// None implies a start.
    pub complete: Option<usize>,
}

impl From<MergeEvent> for DifferentialEvent { fn from(e: MergeEvent) -> Self { DifferentialEvent::Merge(e) } }

/// A merge failed to complete in time.
#[derive(Debug, Clone, Abomonation, Ord, PartialOrd, Eq, PartialEq)]
pub struct MergeShortfall {
    /// Operator identifer.
    pub operator: usize,
    /// Which order of magnitude.
    pub scale: usize,
    /// By how much were we short.
    pub shortfall: usize,
}

impl From<MergeShortfall> for DifferentialEvent { fn from(e: MergeShortfall) -> Self { DifferentialEvent::MergeShortfall(e) } }
<commit_msg>stop the whining<commit_after>//! Loggers and logging events for differential dataflow.

/// Logger for differential dataflow events.
pub type Logger = ::timely::logging::Logger<DifferentialEvent>;

/// Enables logging of differential dataflow events.
pub fn enable<A, W>(worker: &mut timely::worker::Worker<A>, writer: W) -> Option<Box<dyn std::any::Any+'static>>
where
    A: timely::communication::Allocate,
    W: std::io::Write+'static,
{
    let writer = ::timely::dataflow::operators::capture::EventWriter::new(writer);
    let mut logger = ::timely::logging::BatchLogger::new(writer);
    worker
        .log_register()
        .insert::<DifferentialEvent,_>("differential/arrange", move |time, data| logger.publish_batch(time, data))
}

/// Possible different differential events.
#[derive(Debug, Clone, Abomonation, Ord, PartialOrd, Eq, PartialEq)]
pub enum DifferentialEvent {
    /// Batch creation.
    Batch(BatchEvent),
    /// Merge start and stop events.
    Merge(MergeEvent),
    /// Batch dropped when trace dropped.
    Drop(DropEvent),
    /// A merge failed to complete in time.
    MergeShortfall(MergeShortfall),
}

/// Either the start or end of a merge event.
#[derive(Debug, Clone, Abomonation, Ord, PartialOrd, Eq, PartialEq)]
pub struct BatchEvent {
    /// Operator identifier.
    pub operator: usize,
    /// Which order of magnitude.
    pub length: usize,
}

impl From<BatchEvent> for DifferentialEvent { fn from(e: BatchEvent) -> Self { DifferentialEvent::Batch(e) } }

/// Either the start or end of a merge event.
#[derive(Debug, Clone, Abomonation, Ord, PartialOrd, Eq, PartialEq)]
pub struct DropEvent {
    /// Operator identifier.
    pub operator: usize,
    /// Which order of magnitude.
    pub length: usize,
}

impl From<DropEvent> for DifferentialEvent { fn from(e: DropEvent) -> Self { DifferentialEvent::Drop(e) } }

/// Either the start or end of a merge event.
#[derive(Debug, Clone, Abomonation, Ord, PartialOrd, Eq, PartialEq)]
pub struct MergeEvent {
    /// Operator identifier.
    pub operator: usize,
    /// Which order of magnitude.
    pub scale: usize,
    /// Length of first trace.
    pub length1: usize,
    /// Length of second trace.
    pub length2: usize,
    /// None implies a start.
    pub complete: Option<usize>,
}

impl From<MergeEvent> for DifferentialEvent { fn from(e: MergeEvent) -> Self { DifferentialEvent::Merge(e) } }

/// A merge failed to complete in time.
#[derive(Debug, Clone, Abomonation, Ord, PartialOrd, Eq, PartialEq)]
pub struct MergeShortfall {
    /// Operator identifer.
    pub operator: usize,
    /// Which order of magnitude.
    pub scale: usize,
    /// By how much were we short.
    pub shortfall: usize,
}

impl From<MergeShortfall> for DifferentialEvent { fn from(e: MergeShortfall) -> Self { DifferentialEvent::MergeShortfall(e) } }
<|endoftext|>