<commit_before>extern crate cairo;

extern crate gtk;
use gtk::prelude::*;

extern crate glib;

extern crate lazy_static;

use std::rc::{Rc, Weak};
use std::cell::RefCell;

use media::Context;

use toc::{Chapter, Timestamp};

use super::{ChapterTreeManager, ControllerState, ImageSurface, MainController};

lazy_static! {
    static ref EMPTY_REPLACEMENT: String = "-".to_owned();
}

pub struct InfoController {
    drawingarea: gtk::DrawingArea,

    title_lbl: gtk::Label,
    artist_lbl: gtk::Label,
    container_lbl: gtk::Label,
    audio_codec_lbl: gtk::Label,
    video_codec_lbl: gtk::Label,
    duration_lbl: gtk::Label,

    timeline_scale: gtk::Scale,
    repeat_button: gtk::ToggleToolButton,

    chapter_treeview: gtk::TreeView,
    add_chapter_btn: gtk::ToolButton,
    del_chapter_btn: gtk::ToolButton,

    thumbnail: Option<ImageSurface>,

    chapter_manager: ChapterTreeManager,

    duration: u64,
    repeat_chapter: bool,

    main_ctrl: Option<Weak<RefCell<MainController>>>,
}

impl InfoController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<Self>> {
        let add_chapter_btn: gtk::ToolButton = builder
            .get_object("add_chapter-toolbutton")
            .unwrap();
        add_chapter_btn.set_sensitive(false);
        let del_chapter_btn: gtk::ToolButton = builder
            .get_object("remove_chapter-toolbutton")
            .unwrap();
        del_chapter_btn.set_sensitive(false);

        let chapter_manager = ChapterTreeManager::new_from(
            builder.get_object("chapters-tree-store").unwrap()
        );
        let chapter_treeview: gtk::TreeView = builder.get_object("chapter-treeview").unwrap();
        chapter_manager.init_treeview(&chapter_treeview);

        // need a RefCell because the callbacks will use immutable versions of ac
        // when the UI controllers will get a mutable version from time to time
        let this_rc = Rc::new(RefCell::new(InfoController {
            drawingarea: builder.get_object("thumbnail-drawingarea").unwrap(),

            title_lbl: builder.get_object("title-lbl").unwrap(),
            artist_lbl: builder.get_object("artist-lbl").unwrap(),
            container_lbl: builder.get_object("container-lbl").unwrap(),
            audio_codec_lbl: builder.get_object("audio_codec-lbl").unwrap(),
            video_codec_lbl: builder.get_object("video_codec-lbl").unwrap(),
            duration_lbl: builder.get_object("duration-lbl").unwrap(),

            timeline_scale: builder.get_object("timeline-scale").unwrap(),
            repeat_button: builder.get_object("repeat-toolbutton").unwrap(),

            chapter_treeview: chapter_treeview,
            add_chapter_btn: add_chapter_btn,
            del_chapter_btn: del_chapter_btn,

            thumbnail: None,

            chapter_manager: chapter_manager,

            duration: 0,
            repeat_chapter: false,

            main_ctrl: None,
        }));

        {
            let mut this = this_rc.borrow_mut();
            this.cleanup();
            this.chapter_treeview.set_activate_on_single_click(true);
        }

        this_rc
    }

    pub fn register_callbacks(
        this_rc: &Rc<RefCell<Self>>,
        main_ctrl: &Rc<RefCell<MainController>>,
    ) {
        let mut this = this_rc.borrow_mut();

        this.main_ctrl = Some(Rc::downgrade(main_ctrl));

        // Draw thumnail image
        let this_clone = Rc::clone(this_rc);
        this.drawingarea.connect_draw(
            move |drawingarea, cairo_ctx| {
                let this = this_clone.borrow();
                this.draw_thumbnail(drawingarea, cairo_ctx)
            },
        );

        // Scale seek
        let main_ctrl_clone = Rc::clone(main_ctrl);
        this.timeline_scale.connect_change_value(
            move |_, _, value| {
                main_ctrl_clone.borrow_mut().seek(value as u64, false); // approximate (fast)
                Inhibit(true)
            },
        );

        // TreeView seek
        let this_clone = Rc::clone(this_rc);
        let main_ctrl_clone = Rc::clone(main_ctrl);
        this.chapter_treeview.connect_row_activated(
            move |_, tree_path, _| {
                let position_opt = {
                    // get the position first in order to make sure
                    // this is no longer borrowed if main_ctrl::seek is to be called
                    let mut this = this_clone.borrow_mut();
                    match this.chapter_manager.get_iter(tree_path) {
                        Some(iter) => {
                            let position = this.chapter_manager.get_chapter_at_iter(&iter).start();
                            // update position
                            this.tick(position, false);
                            Some(position)
                        }
                        None => None,
                    }
                };

                if let Some(position) = position_opt {
                    main_ctrl_clone.borrow_mut().seek(position, true); // accurate (slow)
                }
            },
        );

        // add chapter
        let this_clone = Rc::clone(this_rc);
        this.add_chapter_btn.connect_clicked(move |_| {
            this_clone.borrow_mut().add_chapter();
        });

        // remove chapter
        let this_clone = Rc::clone(this_rc);
        this.del_chapter_btn.connect_clicked(move |_| {
            this_clone.borrow_mut().remove_chapter();
        });

        // repeat button
        let this_clone = Rc::clone(this_rc);
        this.repeat_button.connect_clicked(move |button| {
            this_clone.borrow_mut().repeat_chapter = button.get_active();
        });
    }

    fn draw_thumbnail(
        &self,
        drawingarea: &gtk::DrawingArea,
        cairo_ctx: &cairo::Context,
    ) -> Inhibit {
        // Thumbnail draw
        if let Some(ref thumbnail) = self.thumbnail {
            let surface = &thumbnail.surface;

            let allocation = drawingarea.get_allocation();
            let alloc_ratio = f64::from(allocation.width) / f64::from(allocation.height);
            let surface_ratio = f64::from(surface.get_width()) / f64::from(surface.get_height());
            let scale = if surface_ratio < alloc_ratio {
                f64::from(allocation.height) / f64::from(surface.get_height())
            } else {
                f64::from(allocation.width) / f64::from(surface.get_width())
            };
            let x = (f64::from(allocation.width) / scale - f64::from(surface.get_width())).abs() /
                2f64;
            let y = (f64::from(allocation.height) / scale - f64::from(surface.get_height()))
                .abs() / 2f64;

            cairo_ctx.scale(scale, scale);
            cairo_ctx.set_source_surface(surface, x, y);
            cairo_ctx.paint();
        }

        Inhibit(true)
    }

    pub fn new_media(&mut self, context: &Context) {
        self.update_duration(context.get_duration());

        {
            let mut info = context.info.lock().expect(
                "InfoController::new_media failed to lock media info",
            );

            info.fix();

            if let Some(thumbnail) = info.thumbnail.take() {
                if let Ok(image) = ImageSurface::from_aligned_image(thumbnail) {
                    self.thumbnail = Some(image);
                }
            };

            self.title_lbl.set_label(&info.get_title().unwrap_or(&EMPTY_REPLACEMENT));
            self.artist_lbl.set_label(&info.get_artist().unwrap_or(&EMPTY_REPLACEMENT));
            self.container_lbl.set_label(&info.get_container().unwrap_or(&EMPTY_REPLACEMENT));
            self.audio_codec_lbl.set_label(&info.get_audio_codec().unwrap_or(&EMPTY_REPLACEMENT));
            self.video_codec_lbl.set_label(&info.get_video_codec().unwrap_or(&EMPTY_REPLACEMENT));

            self.chapter_manager.replace_with(&info.chapters);

            self.update_marks();
        }

        self.add_chapter_btn.set_sensitive(true);
        match self.chapter_manager.get_selected_iter() {
            Some(current_iter) => {
                // position is in a chapter => select it
                self.chapter_treeview.get_selection().select_iter(&current_iter);
                self.del_chapter_btn.set_sensitive(true);
            }
            None =>
                // position is not in any chapter
                self.del_chapter_btn.set_sensitive(false),
        }

        if self.thumbnail.is_some() {
            self.drawingarea.show();
            self.drawingarea.queue_draw();
        } else {
            self.drawingarea.hide();
        }
    }

    fn update_marks(&self) {
        self.timeline_scale.clear_marks();

        let timeline_scale = self.timeline_scale.clone();
        self.chapter_manager.for_each(None, move |chapter| {
            timeline_scale.add_mark(
                chapter.start() as f64,
                gtk::PositionType::Top,
                None,
            );
            true // keep going until the last chapter
        });
    }

    pub fn cleanup(&mut self) {
        self.title_lbl.set_text("");
        self.artist_lbl.set_text("");
        self.container_lbl.set_text("");
        self.audio_codec_lbl.set_text("");
        self.video_codec_lbl.set_text("");
        self.duration_lbl.set_text("00:00.000");
        self.thumbnail = None;
        self.chapter_manager.clear();
        self.timeline_scale.clear_marks();
        self.timeline_scale.set_value(0f64);
        self.duration = 0;
    }

    pub fn update_duration(&mut self, duration: u64) {
        self.duration = duration;
        self.timeline_scale.set_range(0f64, duration as f64);
        self.duration_lbl.set_label(
            &Timestamp::format(duration, false),
        );
    }

    fn repeat_at(main_ctrl: &Option<Weak<RefCell<MainController>>>, position: u64) {
        let main_ctrl_weak = Weak::clone(main_ctrl.as_ref().unwrap());
        gtk::idle_add(move || {
            let main_ctrl_rc = main_ctrl_weak.upgrade().expect(
                "InfoController::tick can't upgrade main_ctrl while repeating chapter",
            );
            main_ctrl_rc.borrow_mut().seek(position, true); // accurate (slow)
            glib::Continue(false)
        });
    }

    pub fn tick(&mut self, position: u64, is_eos: bool) {
        self.timeline_scale.set_value(position as f64);

        let (mut has_changed, prev_selected_iter) =
            self.chapter_manager.update_position(position);

        if self.repeat_chapter {
            // repeat is activated
            if is_eos {
                // postpone chapter selection change until media as synchronized
                has_changed = false;
                self.chapter_manager.rewind();
                InfoController::repeat_at(&self.main_ctrl, 0);
            } else if has_changed {
                if let Some(ref prev_selected_iter) = prev_selected_iter {
                    // discard has_changed because we will be looping on current chapter
                    has_changed = false;

                    // unselect chapter in order to avoid tracing change to current position
                    self.chapter_manager.unselect();
                    InfoController::repeat_at(&self.main_ctrl,
                        self.chapter_manager.get_chapter_at_iter(prev_selected_iter).start()
                    );
                }
            }
        }

        if has_changed {
            // chapter has changed
            match self.chapter_manager.get_selected_iter() {
                Some(current_iter) => {
                    // position is in a chapter => select it
                    self.chapter_treeview.get_selection().select_iter(&current_iter);
                    self.del_chapter_btn.set_sensitive(true);
                }
                None =>
                    // position is not in any chapter
                    if let Some(ref prev_selected_iter) = prev_selected_iter {
                        // but a previous chapter was selected => unselect it
                        self.chapter_treeview.get_selection().unselect_iter(prev_selected_iter);
                        self.del_chapter_btn.set_sensitive(false);
                    },
            }
        }
    }

    pub fn seek(&mut self, position: u64, state: &ControllerState) {
        self.chapter_manager.prepare_for_seek();

        if *state == ControllerState::Paused {
            // force sync
            self.tick(position, false);
        }
    }

    fn get_position(&self) -> u64 {
        let main_ctrl_rc = self.main_ctrl.as_ref().unwrap().upgrade().expect(
            "InfoController::get_position can't upgrade main_ctrl",
        );
        let mut main_ctrl = main_ctrl_rc.borrow_mut();
        main_ctrl.get_position()
    }

    pub fn add_chapter(&mut self) {
        let position = self.get_position();
        if position >= self.duration {
            // can't add a chapter starting at last position
            return;
        }

        if let Some(new_iter) = self.chapter_manager.add_chapter(position, self.duration) {
            self.chapter_treeview.get_selection().select_iter(&new_iter);
            self.update_marks();
            self.del_chapter_btn.set_sensitive(true);
        }
    }

    pub fn remove_chapter(&mut self) {
        match self.chapter_manager.remove_selected_chapter() {
            Some(new_iter) =>
                self.chapter_treeview.get_selection().select_iter(&new_iter),
            None => {
                self.chapter_treeview.get_selection().unselect_all();
                self.del_chapter_btn.set_sensitive(false);
            }
        }

        self.update_marks();
    }

    pub fn export_chapters(&self, context: &mut Context) {
        let mut chapters = Vec::<Chapter>::new();
        self.chapter_manager.for_each(None, |chapter| {
            chapters.push(Chapter::new(
                // use start as chapter id
                &format!("{}", chapter.start_ts().nano_total),
                &chapter.title(),
                chapter.start_ts(),
                chapter.end_ts(),
            ));
            true // keep going until the last chapter
        });

        let mut info = context.info.lock().expect(
            "InfoController::export_chapters failed to lock media info",
        );
        info.chapters = chapters;
    }
}
<commit_msg>InfoController: limit lock on context.info (#75)<commit_after>extern crate cairo;

extern crate gtk;
use gtk::prelude::*;

extern crate glib;

extern crate lazy_static;

use std::rc::{Rc, Weak};
use std::cell::RefCell;

use media::Context;

use toc::{Chapter, Timestamp};

use super::{ChapterTreeManager, ControllerState, ImageSurface, MainController};

lazy_static! {
    static ref EMPTY_REPLACEMENT: String = "-".to_owned();
}

pub struct InfoController {
    drawingarea: gtk::DrawingArea,

    title_lbl: gtk::Label,
    artist_lbl: gtk::Label,
    container_lbl: gtk::Label,
    audio_codec_lbl: gtk::Label,
    video_codec_lbl: gtk::Label,
    duration_lbl: gtk::Label,

    timeline_scale: gtk::Scale,
    repeat_button: gtk::ToggleToolButton,

    chapter_treeview: gtk::TreeView,
    add_chapter_btn: gtk::ToolButton,
    del_chapter_btn: gtk::ToolButton,

    thumbnail: Option<ImageSurface>,

    chapter_manager: ChapterTreeManager,

    duration: u64,
    repeat_chapter: bool,

    main_ctrl: Option<Weak<RefCell<MainController>>>,
}

impl InfoController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<Self>> {
        let add_chapter_btn: gtk::ToolButton = builder
            .get_object("add_chapter-toolbutton")
            .unwrap();
        add_chapter_btn.set_sensitive(false);
        let del_chapter_btn: gtk::ToolButton = builder
            .get_object("remove_chapter-toolbutton")
            .unwrap();
        del_chapter_btn.set_sensitive(false);

        let chapter_manager = ChapterTreeManager::new_from(
            builder.get_object("chapters-tree-store").unwrap()
        );
        let chapter_treeview: gtk::TreeView = builder.get_object("chapter-treeview").unwrap();
        chapter_manager.init_treeview(&chapter_treeview);

        // need a RefCell because the callbacks will use immutable versions of ac
        // when the UI controllers will get a mutable version from time to time
        let this_rc = Rc::new(RefCell::new(InfoController {
            drawingarea: builder.get_object("thumbnail-drawingarea").unwrap(),

            title_lbl: builder.get_object("title-lbl").unwrap(),
            artist_lbl: builder.get_object("artist-lbl").unwrap(),
            container_lbl: builder.get_object("container-lbl").unwrap(),
            audio_codec_lbl: builder.get_object("audio_codec-lbl").unwrap(),
            video_codec_lbl: builder.get_object("video_codec-lbl").unwrap(),
            duration_lbl: builder.get_object("duration-lbl").unwrap(),

            timeline_scale: builder.get_object("timeline-scale").unwrap(),
            repeat_button: builder.get_object("repeat-toolbutton").unwrap(),

            chapter_treeview: chapter_treeview,
            add_chapter_btn: add_chapter_btn,
            del_chapter_btn: del_chapter_btn,

            thumbnail: None,

            chapter_manager: chapter_manager,

            duration: 0,
            repeat_chapter: false,

            main_ctrl: None,
        }));

        {
            let mut this = this_rc.borrow_mut();
            this.cleanup();
            this.chapter_treeview.set_activate_on_single_click(true);
        }

        this_rc
    }

    pub fn register_callbacks(
        this_rc: &Rc<RefCell<Self>>,
        main_ctrl: &Rc<RefCell<MainController>>,
    ) {
        let mut this = this_rc.borrow_mut();

        this.main_ctrl = Some(Rc::downgrade(main_ctrl));

        // Draw thumnail image
        let this_clone = Rc::clone(this_rc);
        this.drawingarea.connect_draw(
            move |drawingarea, cairo_ctx| {
                let this = this_clone.borrow();
                this.draw_thumbnail(drawingarea, cairo_ctx)
            },
        );

        // Scale seek
        let main_ctrl_clone = Rc::clone(main_ctrl);
        this.timeline_scale.connect_change_value(
            move |_, _, value| {
                main_ctrl_clone.borrow_mut().seek(value as u64, false); // approximate (fast)
                Inhibit(true)
            },
        );

        // TreeView seek
        let this_clone = Rc::clone(this_rc);
        let main_ctrl_clone = Rc::clone(main_ctrl);
        this.chapter_treeview.connect_row_activated(
            move |_, tree_path, _| {
                let position_opt = {
                    // get the position first in order to make sure
                    // this is no longer borrowed if main_ctrl::seek is to be called
                    let mut this = this_clone.borrow_mut();
                    match this.chapter_manager.get_iter(tree_path) {
                        Some(iter) => {
                            let position = this.chapter_manager.get_chapter_at_iter(&iter).start();
                            // update position
                            this.tick(position, false);
                            Some(position)
                        }
                        None => None,
                    }
                };

                if let Some(position) = position_opt {
                    main_ctrl_clone.borrow_mut().seek(position, true); // accurate (slow)
                }
            },
        );

        // add chapter
        let this_clone = Rc::clone(this_rc);
        this.add_chapter_btn.connect_clicked(move |_| {
            this_clone.borrow_mut().add_chapter();
        });

        // remove chapter
        let this_clone = Rc::clone(this_rc);
        this.del_chapter_btn.connect_clicked(move |_| {
            this_clone.borrow_mut().remove_chapter();
        });

        // repeat button
        let this_clone = Rc::clone(this_rc);
        this.repeat_button.connect_clicked(move |button| {
            this_clone.borrow_mut().repeat_chapter = button.get_active();
        });
    }

    fn draw_thumbnail(
        &self,
        drawingarea: &gtk::DrawingArea,
        cairo_ctx: &cairo::Context,
    ) -> Inhibit {
        // Thumbnail draw
        if let Some(ref thumbnail) = self.thumbnail {
            let surface = &thumbnail.surface;

            let allocation = drawingarea.get_allocation();
            let alloc_ratio = f64::from(allocation.width) / f64::from(allocation.height);
            let surface_ratio = f64::from(surface.get_width()) / f64::from(surface.get_height());
            let scale = if surface_ratio < alloc_ratio {
                f64::from(allocation.height) / f64::from(surface.get_height())
            } else {
                f64::from(allocation.width) / f64::from(surface.get_width())
            };
            let x = (f64::from(allocation.width) / scale - f64::from(surface.get_width())).abs() /
                2f64;
            let y = (f64::from(allocation.height) / scale - f64::from(surface.get_height()))
                .abs() / 2f64;

            cairo_ctx.scale(scale, scale);
            cairo_ctx.set_source_surface(surface, x, y);
            cairo_ctx.paint();
        }

        Inhibit(true)
    }

    pub fn new_media(&mut self, context: &Context) {
        self.update_duration(context.get_duration());

        {
            let mut info = context.info.lock().expect(
                "InfoController::new_media failed to lock media info",
            );

            info.fix();

            if let Some(thumbnail) = info.thumbnail.take() {
                if let Ok(image) = ImageSurface::from_aligned_image(thumbnail) {
                    self.thumbnail = Some(image);
                }
            };

            self.title_lbl.set_label(&info.get_title().unwrap_or(&EMPTY_REPLACEMENT));
            self.artist_lbl.set_label(&info.get_artist().unwrap_or(&EMPTY_REPLACEMENT));
            self.container_lbl.set_label(&info.get_container().unwrap_or(&EMPTY_REPLACEMENT));
            self.audio_codec_lbl.set_label(&info.get_audio_codec().unwrap_or(&EMPTY_REPLACEMENT));
            self.video_codec_lbl.set_label(&info.get_video_codec().unwrap_or(&EMPTY_REPLACEMENT));

            self.chapter_manager.replace_with(&info.chapters);
        }

        self.update_marks();

        self.add_chapter_btn.set_sensitive(true);
        match self.chapter_manager.get_selected_iter() {
            Some(current_iter) => {
                // position is in a chapter => select it
                self.chapter_treeview.get_selection().select_iter(&current_iter);
                self.del_chapter_btn.set_sensitive(true);
            }
            None =>
                // position is not in any chapter
                self.del_chapter_btn.set_sensitive(false),
        }

        if self.thumbnail.is_some() {
            self.drawingarea.show();
            self.drawingarea.queue_draw();
        } else {
            self.drawingarea.hide();
        }
    }

    fn update_marks(&self) {
        self.timeline_scale.clear_marks();

        let timeline_scale = self.timeline_scale.clone();
        self.chapter_manager.for_each(None, move |chapter| {
            timeline_scale.add_mark(
                chapter.start() as f64,
                gtk::PositionType::Top,
                None,
            );
            true // keep going until the last chapter
        });
    }

    pub fn cleanup(&mut self) {
        self.title_lbl.set_text("");
        self.artist_lbl.set_text("");
        self.container_lbl.set_text("");
        self.audio_codec_lbl.set_text("");
        self.video_codec_lbl.set_text("");
        self.duration_lbl.set_text("00:00.000");
        self.thumbnail = None;
        self.chapter_manager.clear();
        self.timeline_scale.clear_marks();
        self.timeline_scale.set_value(0f64);
        self.duration = 0;
    }

    pub fn update_duration(&mut self, duration: u64) {
        self.duration = duration;
        self.timeline_scale.set_range(0f64, duration as f64);
        self.duration_lbl.set_label(
            &Timestamp::format(duration, false),
        );
    }

    fn repeat_at(main_ctrl: &Option<Weak<RefCell<MainController>>>, position: u64) {
        let main_ctrl_weak = Weak::clone(main_ctrl.as_ref().unwrap());
        gtk::idle_add(move || {
            let main_ctrl_rc = main_ctrl_weak.upgrade().expect(
                "InfoController::tick can't upgrade main_ctrl while repeating chapter",
            );
            main_ctrl_rc.borrow_mut().seek(position, true); // accurate (slow)
            glib::Continue(false)
        });
    }

    pub fn tick(&mut self, position: u64, is_eos: bool) {
        self.timeline_scale.set_value(position as f64);

        let (mut has_changed, prev_selected_iter) =
            self.chapter_manager.update_position(position);

        if self.repeat_chapter {
            // repeat is activated
            if is_eos {
                // postpone chapter selection change until media as synchronized
                has_changed = false;
                self.chapter_manager.rewind();
                InfoController::repeat_at(&self.main_ctrl, 0);
            } else if has_changed {
                if let Some(ref prev_selected_iter) = prev_selected_iter {
                    // discard has_changed because we will be looping on current chapter
                    has_changed = false;

                    // unselect chapter in order to avoid tracing change to current position
                    self.chapter_manager.unselect();
                    InfoController::repeat_at(&self.main_ctrl,
                        self.chapter_manager.get_chapter_at_iter(prev_selected_iter).start()
                    );
                }
            }
        }

        if has_changed {
            // chapter has changed
            match self.chapter_manager.get_selected_iter() {
                Some(current_iter) => {
                    // position is in a chapter => select it
                    self.chapter_treeview.get_selection().select_iter(&current_iter);
                    self.del_chapter_btn.set_sensitive(true);
                }
                None =>
                    // position is not in any chapter
                    if let Some(ref prev_selected_iter) = prev_selected_iter {
                        // but a previous chapter was selected => unselect it
                        self.chapter_treeview.get_selection().unselect_iter(prev_selected_iter);
                        self.del_chapter_btn.set_sensitive(false);
                    },
            }
        }
    }

    pub fn seek(&mut self, position: u64, state: &ControllerState) {
        self.chapter_manager.prepare_for_seek();

        if *state == ControllerState::Paused {
            // force sync
            self.tick(position, false);
        }
    }

    fn get_position(&self) -> u64 {
        let main_ctrl_rc = self.main_ctrl.as_ref().unwrap().upgrade().expect(
            "InfoController::get_position can't upgrade main_ctrl",
        );
        let mut main_ctrl = main_ctrl_rc.borrow_mut();
        main_ctrl.get_position()
    }

    pub fn add_chapter(&mut self) {
        let position = self.get_position();
        if position >= self.duration {
            // can't add a chapter starting at last position
            return;
        }

        if let Some(new_iter) = self.chapter_manager.add_chapter(position, self.duration) {
            self.chapter_treeview.get_selection().select_iter(&new_iter);
            self.update_marks();
            self.del_chapter_btn.set_sensitive(true);
        }
    }

    pub fn remove_chapter(&mut self) {
        match self.chapter_manager.remove_selected_chapter() {
            Some(new_iter) =>
                self.chapter_treeview.get_selection().select_iter(&new_iter),
            None => {
                self.chapter_treeview.get_selection().unselect_all();
                self.del_chapter_btn.set_sensitive(false);
            }
        }

        self.update_marks();
    }

    pub fn export_chapters(&self, context: &mut Context) {
        let mut chapters = Vec::<Chapter>::new();
        self.chapter_manager.for_each(None, |chapter| {
            chapters.push(Chapter::new(
                // use start as chapter id
                &format!("{}", chapter.start_ts().nano_total),
                &chapter.title(),
                chapter.start_ts(),
                chapter.end_ts(),
            ));
            true // keep going until the last chapter
        });

        let mut info = context.info.lock().expect(
            "InfoController::export_chapters failed to lock media info",
        );
        info.chapters = chapters;
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(dyn_trait)]

use std::fmt::Display;

static BYTE: u8 = 33;

fn main() {
    let x: &(dyn 'static + Display) = &BYTE;
    let y: Box<dyn Display + 'static> = Box::new(BYTE);
    let _: &dyn (Display) = &BYTE;
    let _: &dyn (::std::fmt::Display) = &BYTE;
    let xstr = format!("{}", x);
    let ystr = format!("{}", y);
    assert_eq!(xstr, "33");
    assert_eq!(ystr, "33");
}
<commit_msg>ignore-pretty on dyn trait test<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-pretty `dyn ::foo` parses differently in the current epoch

#![feature(dyn_trait)]

use std::fmt::Display;

static BYTE: u8 = 33;

fn main() {
    let x: &(dyn 'static + Display) = &BYTE;
    let y: Box<dyn Display + 'static> = Box::new(BYTE);
    let _: &dyn (Display) = &BYTE;
    let _: &dyn (::std::fmt::Display) = &BYTE;
    let xstr = format!("{}", x);
    let ystr = format!("{}", y);
    assert_eq!(xstr, "33");
    assert_eq!(ystr, "33");
}
<|endoftext|>


<commit_before>use std;

import std::ctypes::*;

fn foo_float() -> m_float { ret 0.0 as m_float; }
fn bar_float() -> float { be foo_float() as float; }

fn foo_int() -> m_int { ret 0 as m_int; }
fn bar_int() -> int { be foo_int() as int; }

fn foo_uint() -> m_uint { ret 0u as m_uint; }
fn bar_uint() -> uint { be foo_uint() as uint; }

fn foo_long() -> long { ret 0 as long; }
fn bar_long() -> int { be foo_long() as int; }

fn foo_ulong() -> ulong { ret 0u as ulong; }
fn bar_ulong() -> uint { be foo_uint() as uint; }

fn main() {
    assert bar_float() == 0.0;
    assert bar_int() == 0;
    assert bar_uint() == 0u;
    assert bar_long() == 0;
    assert bar_ulong() == 0u;
}<commit_msg>Restore accidentally overwritten test<commit_after>use std;
import std::float;

fn main() {
  let nan = float::NaN;
  assert(float::isNaN(nan));

  let inf = float::infinity;
  assert(-inf == float::neg_infinity);

  assert( nan !=  nan);
  assert( nan != -nan);
  assert(-nan != -nan);
  assert(-nan !=  nan);

  assert( nan !=   1.);
  assert( nan !=   0.);
  assert( nan !=  inf);
  assert( nan != -inf);

  assert(  1. !=  nan);
  assert(  0. !=  nan);
  assert( inf !=  nan);
  assert(-inf !=  nan);

  assert(!( nan ==  nan));
  assert(!( nan == -nan));
  assert(!( nan ==   1.));
  assert(!( nan ==   0.));
  assert(!( nan ==  inf));
  assert(!( nan == -inf));
  assert(!(  1. ==  nan));
  assert(!(  0. ==  nan));
  assert(!( inf ==  nan));
  assert(!(-inf ==  nan));
  assert(!(-nan ==  nan));
  assert(!(-nan == -nan));

  assert(!( nan >  nan));
  assert(!( nan > -nan));
  assert(!( nan >   0.));
  assert(!( nan >  inf));
  assert(!( nan > -inf));
  assert(!(  0. >  nan));
  assert(!( inf >  nan));
  assert(!(-inf >  nan));
  assert(!(-nan >  nan));

  assert(!(nan <   0.));
  assert(!(nan <   1.));
  assert(!(nan <  -1.));
  assert(!(nan <  inf));
  assert(!(nan < -inf));
  assert(!(nan <  nan));
  assert(!(nan < -nan));

  assert(!(  0. < nan));
  assert(!(  1. < nan));
  assert(!( -1. < nan));
  assert(!( inf < nan));
  assert(!(-inf < nan));
  assert(!(-nan < nan));

  assert(float::isNaN(nan + inf));
  assert(float::isNaN(nan + -inf));
  assert(float::isNaN(nan + 0.));
  assert(float::isNaN(nan + 1.));
  assert(float::isNaN(nan * 1.));
  assert(float::isNaN(nan / 1.));
  assert(float::isNaN(nan / 0.));
  assert(float::isNaN(0. / 0.));
  assert(float::isNaN(-inf + inf));
  assert(float::isNaN(inf - inf));

  assert(!float::isNaN(-1.));
  assert(!float::isNaN(0.));
  assert(!float::isNaN(0.1));
  assert(!float::isNaN(1.));
  assert(!float::isNaN(inf));
  assert(!float::isNaN(-inf));
  assert(!float::isNaN(1./-inf));
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use opts;
use resource_files::resources_dir_path;
use rustc_serialize::json::{Json, ToJson};
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};

lazy_static! {
    static ref PREFS: Arc<Mutex<HashMap<String, Pref>>> = {
        let prefs = read_prefs().unwrap_or(HashMap::new());
        Arc::new(Mutex::new(prefs))
    };
}

#[derive(PartialEq, Clone, Debug)]
pub enum PrefValue {
    Boolean(bool),
    String(String),
    Missing
}

impl PrefValue {
    pub fn from_json(data: Json) -> Result<PrefValue, ()> {
        let value = match data {
            Json::Boolean(x) => PrefValue::Boolean(x),
            Json::String(x) => PrefValue::String(x),
            _ => return Err(())
        };
        Ok(value)
    }

    pub fn as_boolean(&self) -> Option<bool> {
        match *self {
            PrefValue::Boolean(value) => {
                Some(value)
            },
            _ => None
        }
    }

    pub fn as_string(&self) -> Option<&str> {
        match *self {
            PrefValue::String(ref value) => {
                Some(&value)
            },
            _ => None
        }
    }
}

impl ToJson for PrefValue {
    fn to_json(&self) -> Json {
        match *self {
            PrefValue::Boolean(x) => {
                Json::Boolean(x)
            },
            PrefValue::String(ref x) => {
                Json::String(x.clone())
            }
            PrefValue::Missing => Json::Null
        }
    }
}

#[derive(Debug)]
pub enum Pref {
    NoDefault(Arc<PrefValue>),
    WithDefault(Arc<PrefValue>, Option<Arc<PrefValue>>)
}

impl Pref {
    pub fn new(value: PrefValue) -> Pref {
        Pref::NoDefault(Arc::new(value))
    }

    fn new_default(value: PrefValue) -> Pref {
        Pref::WithDefault(Arc::new(value), None)
    }

    fn from_json(data: Json) -> Result<Pref, ()> {
        let value = try!(PrefValue::from_json(data));
        Ok(Pref::new_default(value))
    }

    pub fn value(&self) -> &Arc<PrefValue> {
        match *self {
            Pref::NoDefault(ref x) => x,
            Pref::WithDefault(ref default, ref override_value) => {
                match *override_value {
                    Some(ref x) => x,
                    None => default
                }
            }
        }
    }

    fn set(&mut self, value: PrefValue) {
        // TODO - this should error if we try to override a pref of one type
        // with a value of a different type
        match *self {
            Pref::NoDefault(ref mut pref_value) => {
                *pref_value = Arc::new(value)
            },
            Pref::WithDefault(_, ref mut override_value) => {
                *override_value = Some(Arc::new(value))
            }
        }
    }
}

impl ToJson for Pref {
    fn to_json(&self) -> Json {
        self.value().to_json()
    }
}

pub fn read_prefs_from_file<T>(mut file: T)
    -> Result<HashMap<String, Pref>, ()> where T: Read {
    let json = try!(Json::from_reader(&mut file).or_else(|e| {
        println!("Ignoring invalid JSON in preferences: {:?}.", e);
        Err(())
    }));

    let mut prefs = HashMap::new();
    if let Json::Object(obj) = json {
        for (name, value) in obj.into_iter() {
            match Pref::from_json(value) {
                Ok(x) => {
                    prefs.insert(name, x);
                },
                Err(_) => println!("Ignoring non-boolean/string preference value for {:?}", name)
            }
        }
    }
    Ok(prefs)
}

pub fn extend_prefs(extension: HashMap<String, Pref>) {
    PREFS.lock().unwrap().extend(extension);
}

pub fn add_user_prefs() {
    if let Some(ref dir) = opts::get().profile_dir {
        let mut path = PathBuf::from(dir);
        path.push("prefs.json");
        if let Ok(file) = File::open(path) {
            if let Ok(prefs) = read_prefs_from_file(file) {
                extend_prefs(prefs);
            }
        } else {
            println!("Error opening prefs.json from profile_dir");
        }
    }
}

fn read_prefs() -> Result<HashMap<String, Pref>, ()> {
    let mut path = resources_dir_path();
    path.push("prefs.json");

    let file = try!(File::open(path).or_else(|e| {
        println!("Error opening preferences: {:?}.", e);
        Err(())
    }));

    read_prefs_from_file(file)
}

pub fn get_pref(name: &str) -> Arc<PrefValue> {
    PREFS.lock().unwrap().get(name).map_or(Arc::new(PrefValue::Missing), |x| x.value().clone())
}

pub fn set_pref(name: &str, value: PrefValue) {
    let mut prefs = PREFS.lock().unwrap();
    if let Some(pref) = prefs.get_mut(name) {
        pref.set(value);
        return;
    }
    prefs.insert(name.to_owned(), Pref::new(value));
}

pub fn reset_pref(name: &str) -> Arc<PrefValue> {
    let mut prefs = PREFS.lock().unwrap();
    let result = match prefs.get_mut(name) {
        None => return Arc::new(PrefValue::Missing),
        Some(&mut Pref::NoDefault(_)) => Arc::new(PrefValue::Missing),
        Some(&mut Pref::WithDefault(ref default, ref mut set_value)) => {
            *set_value = None;
            default.clone()
        },
    };
    if *result == PrefValue::Missing {
        prefs.remove(name);
    }
    result
}

pub fn reset_all_prefs() {
    let names = {
        PREFS.lock().unwrap().keys().cloned().collect::<Vec<String>>()
    };
    for name in names.iter() {
        reset_pref(name);
    }
}
<commit_msg>Print errors to stderr<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use opts;
use resource_files::resources_dir_path;
use rustc_serialize::json::{Json, ToJson};
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, Write, stderr};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};

lazy_static! {
    static ref PREFS: Arc<Mutex<HashMap<String, Pref>>> = {
        let prefs = read_prefs().unwrap_or(HashMap::new());
        Arc::new(Mutex::new(prefs))
    };
}

#[derive(PartialEq, Clone, Debug)]
pub enum PrefValue {
    Boolean(bool),
    String(String),
    Missing
}

impl PrefValue {
    pub fn from_json(data: Json) -> Result<PrefValue, ()> {
        let value = match data {
            Json::Boolean(x) => PrefValue::Boolean(x),
            Json::String(x) => PrefValue::String(x),
            _ => return Err(())
        };
        Ok(value)
    }

    pub fn as_boolean(&self) -> Option<bool> {
        match *self {
            PrefValue::Boolean(value) => {
                Some(value)
            },
            _ => None
        }
    }

    pub fn as_string(&self) -> Option<&str> {
        match *self {
            PrefValue::String(ref value) => {
                Some(&value)
            },
            _ => None
        }
    }
}

impl ToJson for PrefValue {
    fn to_json(&self) -> Json {
        match *self {
            PrefValue::Boolean(x) => {
                Json::Boolean(x)
            },
            PrefValue::String(ref x) => {
                Json::String(x.clone())
            }
            PrefValue::Missing => Json::Null
        }
    }
}

#[derive(Debug)]
pub enum Pref {
    NoDefault(Arc<PrefValue>),
    WithDefault(Arc<PrefValue>, Option<Arc<PrefValue>>)
}

impl Pref {
    pub fn new(value: PrefValue) -> Pref {
        Pref::NoDefault(Arc::new(value))
    }

    fn new_default(value: PrefValue) -> Pref {
        Pref::WithDefault(Arc::new(value), None)
    }

    fn from_json(data: Json) -> Result<Pref, ()> {
        let value = try!(PrefValue::from_json(data));
        Ok(Pref::new_default(value))
    }

    pub fn value(&self) -> &Arc<PrefValue> {
        match *self {
            Pref::NoDefault(ref x) => x,
            Pref::WithDefault(ref default, ref override_value) => {
                match *override_value {
                    Some(ref x) => x,
                    None => default
                }
            }
        }
    }

    fn set(&mut self, value: PrefValue) {
        // TODO - this should error if we try to override a pref of one type
        // with a value of a different type
        match *self {
            Pref::NoDefault(ref mut pref_value) => {
                *pref_value = Arc::new(value)
            },
            Pref::WithDefault(_, ref mut override_value) => {
                *override_value = Some(Arc::new(value))
            }
        }
    }
}

impl ToJson for Pref {
    fn to_json(&self) -> Json {
        self.value().to_json()
    }
}

pub fn read_prefs_from_file<T>(mut file: T)
    -> Result<HashMap<String, Pref>, ()> where T: Read {
    let json = try!(Json::from_reader(&mut file).or_else(|e| {
        println!("Ignoring invalid JSON in preferences: {:?}.", e);
        Err(())
    }));

    let mut prefs = HashMap::new();
    if let Json::Object(obj) = json {
        for (name, value) in obj.into_iter() {
            match Pref::from_json(value) {
                Ok(x) => {
                    prefs.insert(name, x);
                },
                Err(_) => println!("Ignoring non-boolean/string preference value for {:?}", name)
            }
        }
    }
    Ok(prefs)
}

pub fn extend_prefs(extension: HashMap<String, Pref>) {
    PREFS.lock().unwrap().extend(extension);
}

pub fn add_user_prefs() {
    if let Some(ref dir) = opts::get().profile_dir {
        let mut path = PathBuf::from(dir);
        path.push("prefs.json");
        if let Ok(file) = File::open(path) {
            if let Ok(prefs) = read_prefs_from_file(file) {
                extend_prefs(prefs);
            }
        } else {
            writeln!(&mut stderr(), "Error opening prefs.json from profile_dir")
                .expect("failed printing to stderr");
        }
    }
}

fn read_prefs() -> Result<HashMap<String, Pref>, ()> {
    let mut path = resources_dir_path();
    path.push("prefs.json");

    let file = try!(File::open(path).or_else(|e| {
        writeln!(&mut stderr(), "Error opening preferences: {:?}.", e)
            .expect("failed printing to stderr");
        Err(())
    }));

    read_prefs_from_file(file)
}

pub fn get_pref(name: &str) -> Arc<PrefValue> {
    PREFS.lock().unwrap().get(name).map_or(Arc::new(PrefValue::Missing), |x| x.value().clone())
}

pub fn set_pref(name: &str, value: PrefValue) {
    let mut prefs = PREFS.lock().unwrap();
    if let Some(pref) = prefs.get_mut(name) {
        pref.set(value);
        return;
    }
    prefs.insert(name.to_owned(), Pref::new(value));
}

pub fn reset_pref(name: &str) -> Arc<PrefValue> {
    let mut prefs = PREFS.lock().unwrap();
    let result = match prefs.get_mut(name) {
        None => return Arc::new(PrefValue::Missing),
        Some(&mut Pref::NoDefault(_)) => Arc::new(PrefValue::Missing),
        Some(&mut Pref::WithDefault(ref default, ref mut set_value)) => {
            *set_value = None;
            default.clone()
        },
    };
    if *result == PrefValue::Missing {
        prefs.remove(name);
    }
    result
}

pub fn reset_all_prefs() {
    let names = {
        PREFS.lock().unwrap().keys().cloned().collect::<Vec<String>>()
    };
    for name in names.iter() {
        reset_pref(name);
    }
}
<|endoftext|>


<commit_before>use kernel_micro::{include_file, MicroKernel};

/// A microkernel for R
pub fn new() -> MicroKernel {
    MicroKernel::new(
        "r-micro",
        &["r"],
        &["linux", "macos", "windows"],
        &["linux", "macos"],
        ("Rscript", "*"),
        &["{{script}}"],
        include_file!("r-kernel.r"),
        &[include_file!("r-codec.r")],
        "{{name}} <- decode_value(\"{{json}}\")",
        "{{name}}",
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use kernel::{
        eyre::{bail, Result},
        stencila_schema::Node,
        KernelTrait,
    };
    use once_cell::sync::Lazy;
    use test_utils::{assert_json_eq, assert_json_is};
    use tokio::sync::Mutex;

    // Make sure that only one test runs at any one time
    // This is to avoid `install.packages` being run in parallel.
    // Previous the `serial_test` crate was used for this but did not
    // seem to provide necessary guarantee.
    static QUEUE: Lazy<Mutex<()>> = Lazy::new(Mutex::default);

    async fn skip_or_kernel() -> Result<MicroKernel> {
        let mut kernel = new();
        if !kernel.available().await {
            eprintln!("R not available on this machine");
            bail!("Skipping")
        } else {
            kernel.start().await?;
        }

        Ok(kernel)
    }

    // Run these tests serially to avoid parallel installation of dependencies
    // which may interfere with each other.

    /// Tests of basic functionality
    /// This test is replicated in all the microkernels.
    /// Other test should be written for language specific quirks and regressions.
    #[tokio::test]
    async fn basics() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        // The execution context should start off empty
        let (outputs, messages) = kernel.exec("ls()").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [[]]);

        // Assign a variable and output it
        let (outputs, messages) = kernel.exec("a <- 2\na").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [[2]]);

        // The execution context should now have the var
        let (outputs, messages) = kernel.exec("ls()").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [["a"]]);

        // Print the variable twice and then output it
        let (outputs, messages) = kernel.exec("print(a)\nprint(a)\na").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [[2], [2], [2]]);

        // Syntax error
        let (outputs, messages) = kernel.exec("bad ^ # syntax").await?;
        assert_json_is!(messages[0].error_type, "SyntaxError");
        assert_json_is!(
            messages[0].error_message,
            "<text>:2:0: unexpected end of input\n1: bad ^ # syntax\n   ^"
        );
        assert_json_is!(outputs, []);

        // Runtime error
        let (outputs, messages) = kernel.exec("foo").await?;
        assert_json_is!(messages[0].error_type, "RuntimeError");
        assert_json_is!(messages[0].error_message, "object 'foo' not found");
        assert_json_is!(outputs, []);

        // Set and get another variable
        kernel.set("b", Node::Integer(3)).await?;
        let b = kernel.get("b").await?;
        assert_json_is!(b, [3]);

        // Use both variables
        let (outputs, messages) = kernel.exec("a*b").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [[6]]);

        Ok(())
    }

    /// Test that an assignment on the last line does not generate an output
    #[tokio::test]
    async fn assignment_no_output() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        let (outputs, messages) = kernel.exec("a <- 1").await?;
        assert!(messages.is_empty());
        assert_json_is!(outputs, []);

        let (outputs, messages) = kernel.exec("b = 2").await?;
        assert!(messages.is_empty());
        assert_json_is!(outputs, []);

        let (outputs, messages) = kernel.exec("print(a)\nprint(b)\na_b <- a + b").await?;
        assert!(messages.is_empty());
        assert_json_is!(outputs, [[1], [2]]);

        Ok(())
    }

    #[tokio::test]
    async fn encode_general() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        // Null, booleans, integers, numbers, strings
        let (outputs, messages) = kernel
            .exec("list(NULL, TRUE, FALSE, 1, 1.23456789, 'str')")
            .await?;
        assert_json_is!(messages, []);
        assert_json_is!(
            outputs,
            [[null, [true], [false], [1], [1.23456789], ["str"]]]
        );

        // Arrays
        let (outputs, messages) = kernel.exec("1:5").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [[1, 2, 3, 4, 5]]);

        // Objects
        let (outputs, messages) = kernel.exec("list(a=1, b=list(c=2))").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [{"type": "Entity"}]);
        // TODO: correct output when deserialization of Node::Object is working
        //assert_json_is!(outputs, json!([{"a": [1], "b": {"c": [2]}}]));

        // Matrix
        let (outputs, messages) = kernel.exec("matrix(c(1:4), 2, 2)").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [[[1, 3], [2, 4]]]);

        Ok(())
    }

    #[tokio::test]
    async fn encode_dataframes() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        let (outputs, messages) = kernel
            .exec(
                r#"data.frame(
    a = 1:2,
    b = c(TRUE, FALSE),
    c = c("x", "y"),
    d = factor(c("X", "Y"), levels = c("X", "Y", "Z")),
    stringsAsFactors = FALSE
)"#,
            )
            .await?;
        assert_json_is!(messages, []);
        let dt = match &outputs[0] {
            Node::Datatable(dt) => dt.clone(),
            _ => bail!("unexpected type {:?}", outputs[0]),
        };
        assert_eq!(
            dt.columns
                .iter()
                .map(|column| column.name.as_str())
                .collect::<Vec<&str>>(),
            vec!["a", "b", "c", "d"]
        );
        assert_json_is!(
            dt.columns[0].validator.as_ref().unwrap().items_validator,
            { "type": "NumberValidator"}
        );
        assert_json_is!(
            dt.columns[1].validator.as_ref().unwrap().items_validator,
            { "type": "BooleanValidator"}
        );
        assert_json_is!(
            dt.columns[2].validator.as_ref().unwrap().items_validator,
            { "type": "StringValidator"}
        );
        assert_json_is!(
            dt.columns[3].validator.as_ref().unwrap().items_validator,
            {
                "type": "EnumValidator",
                "values": ["X", "Y", "Z"]
            }
        );

        let (outputs, messages) = kernel.exec("mtcars").await?;
        assert_json_is!(messages, []);
        let dt = match &outputs[0] {
            Node::Datatable(dt) => dt.clone(),
            _ => bail!("unexpected type {:?}", outputs[0]),
        };
        assert_eq!(
            dt.columns
                .iter()
                .map(|column| column.name.as_str())
                .collect::<Vec<&str>>(),
            vec![
                "name", "mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear",
                "carb"
            ]
        );
        assert_json_is!(
            dt.columns[0].validator.as_ref().unwrap().items_validator,
            { "type": "StringValidator"}
        );
        assert_json_is!(
            dt.columns[1].validator.as_ref().unwrap().items_validator,
            { "type": "NumberValidator"}
        );

        let (outputs, messages) = kernel.exec("chickwts").await?;
        assert_json_is!(messages, []);
        let dt = match &outputs[0] {
            Node::Datatable(dt) => dt.clone(),
            _ => bail!("unexpected type {:?}", outputs[0]),
        };
        assert_eq!(
            dt.columns
                .iter()
                .map(|column| column.name.as_str())
                .collect::<Vec<&str>>(),
            vec!["weight", "feed"]
        );
        assert_json_is!(
            dt.columns[0].validator.as_ref().unwrap().items_validator,
            { "type": "NumberValidator"}
        );
        assert_json_is!(
            dt.columns[1].validator.as_ref().unwrap().items_validator,
            {
                "type": "EnumValidator",
                "values": ["casein", "horsebean", "linseed", "meatmeal", "soybean", "sunflower"]
            }
        );

        Ok(())
    }

    #[tokio::test]
    async fn encode_plots() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        for code in ["plot(1)", "hist(rnorm(1000), breaks=30)"] {
            let (outputs, messages) = kernel.exec(code).await?;
            assert_json_is!(messages, []);
            let image = match &outputs[0] {
                Node::ImageObject(dt) => dt.clone(),
                _ => bail!("unexpected type {:?}", outputs[0]),
            };
            assert!(image.content_url.starts_with("data:image/png;base64,"));
        }

        Ok(())
    }

    /// Test forking
    #[tokio::test]
    async fn fork() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => {
                if kernel.forkable().await {
                    kernel
                } else {
                    eprintln!("Not forkable on this OS");
                    return Ok(());
                }
            }
            Err(..) => return Ok(()),
        };

        // In the kernel import a module and assign a variable
        let (outputs, messages) = kernel.exec("var = runif(1)\nvar").await?;
        assert_json_is!(messages, []);
        assert_eq!(outputs.len(), 1);
        let var = outputs[0].clone();

        // Now fork-exec. The fork should be able to use the module and access the
        // variable but any change to variable should not change its value in the parent kernel
        let (outputs, messages) = kernel.fork_exec("print(var)\nvar = runif(1)").await?;
        assert_json_is!(messages, []);
        assert_eq!(outputs.len(), 1);
        assert_json_is!(outputs[0], var);

        // Back in the parent kernel, var should still have its original value
        assert_json_eq!(var, kernel.get("var").await?);
        let (outputs, messages) = kernel.exec("var").await?;
        assert_json_is!(messages, []);
        assert_eq!(outputs.len(), 1);

        Ok(())
    }
}
<commit_msg>test(R kernel): Fix object output test<commit_after>use kernel_micro::{include_file, MicroKernel};

/// A microkernel for R
pub fn new() -> MicroKernel {
    MicroKernel::new(
        "r-micro",
        &["r"],
        &["linux", "macos", "windows"],
        &["linux", "macos"],
        ("Rscript", "*"),
        &["{{script}}"],
        include_file!("r-kernel.r"),
        &[include_file!("r-codec.r")],
        "{{name}} <- decode_value(\"{{json}}\")",
        "{{name}}",
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use kernel::{
        eyre::{bail, Result},
        stencila_schema::Node,
        KernelTrait,
    };
    use once_cell::sync::Lazy;
    use test_utils::{assert_json_eq, assert_json_is};
    use tokio::sync::Mutex;

    // Make sure that only one test runs at any one time
    // This is to avoid `install.packages` being run in parallel.
    // Previous the `serial_test` crate was used for this but did not
    // seem to provide necessary guarantee.
    static QUEUE: Lazy<Mutex<()>> = Lazy::new(Mutex::default);

    async fn skip_or_kernel() -> Result<MicroKernel> {
        let mut kernel = new();
        if !kernel.available().await {
            eprintln!("R not available on this machine");
            bail!("Skipping")
        } else {
            kernel.start().await?;
        }

        Ok(kernel)
    }

    // Run these tests serially to avoid parallel installation of dependencies
    // which may interfere with each other.

    /// Tests of basic functionality
    /// This test is replicated in all the microkernels.
    /// Other test should be written for language specific quirks and regressions.
    #[tokio::test]
    async fn basics() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        // The execution context should start off empty
        let (outputs, messages) = kernel.exec("ls()").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [[]]);

        // Assign a variable and output it
        let (outputs, messages) = kernel.exec("a <- 2\na").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [[2]]);

        // The execution context should now have the var
        let (outputs, messages) = kernel.exec("ls()").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [["a"]]);

        // Print the variable twice and then output it
        let (outputs, messages) = kernel.exec("print(a)\nprint(a)\na").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [[2], [2], [2]]);

        // Syntax error
        let (outputs, messages) = kernel.exec("bad ^ # syntax").await?;
        assert_json_is!(messages[0].error_type, "SyntaxError");
        assert_json_is!(
            messages[0].error_message,
            "<text>:2:0: unexpected end of input\n1: bad ^ # syntax\n   ^"
        );
        assert_json_is!(outputs, []);

        // Runtime error
        let (outputs, messages) = kernel.exec("foo").await?;
        assert_json_is!(messages[0].error_type, "RuntimeError");
        assert_json_is!(messages[0].error_message, "object 'foo' not found");
        assert_json_is!(outputs, []);

        // Set and get another variable
        kernel.set("b", Node::Integer(3)).await?;
        let b = kernel.get("b").await?;
        assert_json_is!(b, [3]);

        // Use both variables
        let (outputs, messages) = kernel.exec("a*b").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [[6]]);

        Ok(())
    }

    /// Test that an assignment on the last line does not generate an output
    #[tokio::test]
    async fn assignment_no_output() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        let (outputs, messages) = kernel.exec("a <- 1").await?;
        assert!(messages.is_empty());
        assert_json_is!(outputs, []);

        let (outputs, messages) = kernel.exec("b = 2").await?;
        assert!(messages.is_empty());
        assert_json_is!(outputs, []);

        let (outputs, messages) = kernel.exec("print(a)\nprint(b)\na_b <- a + b").await?;
        assert!(messages.is_empty());
        assert_json_is!(outputs, [[1], [2]]);

        Ok(())
    }

    #[tokio::test]
    async fn encode_general() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        // Null, booleans, integers, numbers, strings
        let (outputs, messages) = kernel
            .exec("list(NULL, TRUE, FALSE, 1, 1.23456789, 'str')")
            .await?;
        assert_json_is!(messages, []);
        assert_json_is!(
            outputs,
            [[null, [true], [false], [1], [1.23456789], ["str"]]]
        );

        // Arrays
        let (outputs, messages) = kernel.exec("1:5").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [[1, 2, 3, 4, 5]]);

        // Objects
        let (outputs, messages) = kernel.exec("list(a=1, b=list(c=2))").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [{"a": [1], "b": {"c": [2]}}]);

        // Matrix
        let (outputs, messages) = kernel.exec("matrix(c(1:4), 2, 2)").await?;
        assert_json_is!(messages, []);
        assert_json_is!(outputs, [[[1, 3], [2, 4]]]);

        Ok(())
    }

    #[tokio::test]
    async fn encode_dataframes() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        let (outputs, messages) = kernel
            .exec(
                r#"data.frame(
    a = 1:2,
    b = c(TRUE, FALSE),
    c = c("x", "y"),
    d = factor(c("X", "Y"), levels = c("X", "Y", "Z")),
    stringsAsFactors = FALSE
)"#,
            )
            .await?;
        assert_json_is!(messages, []);
        let dt = match &outputs[0] {
            Node::Datatable(dt) => dt.clone(),
            _ => bail!("unexpected type {:?}", outputs[0]),
        };
        assert_eq!(
            dt.columns
                .iter()
                .map(|column| column.name.as_str())
                .collect::<Vec<&str>>(),
            vec!["a", "b", "c", "d"]
        );
        assert_json_is!(
            dt.columns[0].validator.as_ref().unwrap().items_validator,
            { "type": "NumberValidator"}
        );
        assert_json_is!(
            dt.columns[1].validator.as_ref().unwrap().items_validator,
            { "type": "BooleanValidator"}
        );
        assert_json_is!(
            dt.columns[2].validator.as_ref().unwrap().items_validator,
            { "type": "StringValidator"}
        );
        assert_json_is!(
            dt.columns[3].validator.as_ref().unwrap().items_validator,
            {
                "type": "EnumValidator",
                "values": ["X", "Y", "Z"]
            }
        );

        let (outputs, messages) = kernel.exec("mtcars").await?;
        assert_json_is!(messages, []);
        let dt = match &outputs[0] {
            Node::Datatable(dt) => dt.clone(),
            _ => bail!("unexpected type {:?}", outputs[0]),
        };
        assert_eq!(
            dt.columns
                .iter()
                .map(|column| column.name.as_str())
                .collect::<Vec<&str>>(),
            vec![
                "name", "mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear",
                "carb"
            ]
        );
        assert_json_is!(
            dt.columns[0].validator.as_ref().unwrap().items_validator,
            { "type": "StringValidator"}
        );
        assert_json_is!(
            dt.columns[1].validator.as_ref().unwrap().items_validator,
            { "type": "NumberValidator"}
        );

        let (outputs, messages) = kernel.exec("chickwts").await?;
        assert_json_is!(messages, []);
        let dt = match &outputs[0] {
            Node::Datatable(dt) => dt.clone(),
            _ => bail!("unexpected type {:?}", outputs[0]),
        };
        assert_eq!(
            dt.columns
                .iter()
                .map(|column| column.name.as_str())
                .collect::<Vec<&str>>(),
            vec!["weight", "feed"]
        );
        assert_json_is!(
            dt.columns[0].validator.as_ref().unwrap().items_validator,
            { "type": "NumberValidator"}
        );
        assert_json_is!(
            dt.columns[1].validator.as_ref().unwrap().items_validator,
            {
                "type": "EnumValidator",
                "values": ["casein", "horsebean", "linseed", "meatmeal", "soybean", "sunflower"]
            }
        );

        Ok(())
    }

    #[tokio::test]
    async fn encode_plots() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => kernel,
            Err(..) => return Ok(()),
        };

        for code in ["plot(1)", "hist(rnorm(1000), breaks=30)"] {
            let (outputs, messages) = kernel.exec(code).await?;
            assert_json_is!(messages, []);
            let image = match &outputs[0] {
                Node::ImageObject(dt) => dt.clone(),
                _ => bail!("unexpected type {:?}", outputs[0]),
            };
            assert!(image.content_url.starts_with("data:image/png;base64,"));
        }

        Ok(())
    }

    /// Test forking
    #[tokio::test]
    async fn fork() -> Result<()> {
        let _guard = QUEUE.lock().await;

        let mut kernel = match skip_or_kernel().await {
            Ok(kernel) => {
                if kernel.forkable().await {
                    kernel
                } else {
                    eprintln!("Not forkable on this OS");
                    return Ok(());
                }
            }
            Err(..) => return Ok(()),
        };

        // In the kernel import a module and assign a variable
        let (outputs, messages) = kernel.exec("var = runif(1)\nvar").await?;
        assert_json_is!(messages, []);
        assert_eq!(outputs.len(), 1);
        let var = outputs[0].clone();

        // Now fork-exec. The fork should be able to use the module and access the
        // variable but any change to variable should not change its value in the parent kernel
        let (outputs, messages) = kernel.fork_exec("print(var)\nvar = runif(1)").await?;
        assert_json_is!(messages, []);
        assert_eq!(outputs.len(), 1);
        assert_json_is!(outputs[0], var);

        // Back in the parent kernel, var should still have its original value
        assert_json_eq!(var, kernel.get("var").await?);
        let (outputs, messages) = kernel.exec("var").await?;
        assert_json_is!(messages, []);
        assert_eq!(outputs.len(), 1);

        Ok(())
    }
}
<|endoftext|>


<commit_before>
use wtools::vector;

//

#[test]
fn append_vectors_once_trivial()
{
  println!( "empty vector" );
  let mut dst: Vec<u8> = vec![];
  let src: Vec<Vec<u8>> = vec![];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  let exp: Vec<u8> = vec![];
  assert_eq!( *got, exp );

  println!( "dst - filled, src - empty" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );

  println!( "dst - filled, src - filled, all is unical elements" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 3, 4 ], vec![ 5, 6 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2, 3, 4, 5, 6 ] );

  println!( "dst - filled, src - filled, some is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 3 ], vec![ 4, 2 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2, 3, 4 ] );

  println!( "dst - filled, src - filled, all is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 1 ], vec![ 2, 2 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );

  println!( "dst - filled, src - filled, all is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 2 ], vec![ 2, 1 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );
}

//

#[test]
fn left_index_trivial()
{
  println!( "empty vector" );
  let src: Vec<u8> = vec![];
  let got = vector::left_index( &src, 1, None::<fn(_)> );
  assert_eq!( got, None );

  println!( "filled vector, not matches" );
  let src: Vec<u8> = vec![ 1, 2, 3 ];
  let got = vector::left_index( &src, 4, None::<fn(_)> );
  assert_eq!( got, None );

  println!( "filled vector, matches one" );
  let src: Vec<u8> = vec![ 1, 2, 3 ];
  let got = vector::left_index( &src, 2, None::<fn(_)> );
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches several" );
  let src: Vec<u8> = vec![ 1, 2, 2 ];
  let got = vector::left_index( &src, 2, None::<fn(_)> );
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches all" );
  let src: Vec<u8> = vec![ 2, 2, 2 ];
  let got = vector::left_index( &src, 2, None::<fn(_)> );
  assert_eq!( got, Some( 0 ) );
}

/*
  append_vectors_once_trivial
  left_index_trivial
*/
<commit_msg>Write test routine `left_index_with_equalizer`<commit_after>
use wtools::vector;

//

#[test]
fn append_vectors_once_trivial()
{
  println!( "empty vector" );
  let mut dst: Vec<u8> = vec![];
  let src: Vec<Vec<u8>> = vec![];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  let exp: Vec<u8> = vec![];
  assert_eq!( *got, exp );

  println!( "dst - filled, src - empty" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );

  println!( "dst - filled, src - filled, all is unical elements" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 3, 4 ], vec![ 5, 6 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2, 3, 4, 5, 6 ] );

  println!( "dst - filled, src - filled, some is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 3 ], vec![ 4, 2 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2, 3, 4 ] );

  println!( "dst - filled, src - filled, all is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 1 ], vec![ 2, 2 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );

  println!( "dst - filled, src - filled, all is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 2 ], vec![ 2, 1 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );
}

//

#[test]
fn left_index_trivial()
{
  println!( "empty vector" );
  let src: Vec<u8> = vec![];
  let got = vector::left_index( &src, 1, None::<fn(_, _) -> bool> );
  assert_eq!( got, None );

  println!( "filled vector, not matches" );
  let src: Vec<u8> = vec![ 1, 2, 3 ];
  let got = vector::left_index( &src, 4, None::<fn(_, _) -> bool> );
  assert_eq!( got, None );

  println!( "filled vector, matches one" );
  let src: Vec<u8> = vec![ 1, 2, 3 ];
  let got = vector::left_index( &src, 2, None::<fn(_, _) -> bool> );
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches several" );
  let src: Vec<u8> = vec![ 1, 2, 2 ];
  let got = vector::left_index( &src, 2, None::<fn(_, _) -> bool> );
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches all" );
  let src: Vec<u8> = vec![ 2, 2, 2 ];
  let got = vector::left_index( &src, 2, None::<fn(_, _) -> bool> );
  assert_eq!( got, Some( 0 ) );
}

//

#[test]
fn left_index_with_equalizer()
{
  fn equalizer( src1 : u8, src2 : u8 ) -> bool
  {
    src1 == src2
  }
  println!( "empty vector" );
  let src: Vec<u8> = vec![];
  let got = vector::left_index( &src, 1, Some( equalizer ) );
  assert_eq!( got, None );

  println!( "filled vector, not matches" );
  let src: Vec<u8> = vec![ 1, 2, 3 ];
  let got = vector::left_index( &src, 4, Some( equalizer ) );
  assert_eq!( got, None );

  println!( "filled vector, matches one" );
  let src: Vec<u8> = vec![ 1, 2, 3 ];
  let got = vector::left_index( &src, 2, Some( equalizer ) );
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches several" );
  let src: Vec<u8> = vec![ 1, 2, 2 ];
  let got = vector::left_index( &src, 2, Some( equalizer ) );
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches all" );
  let src: Vec<u8> = vec![ 2, 2, 2 ];
  let got = vector::left_index( &src, 2, Some( equalizer ) );
  assert_eq!( got, Some( 0 ) );
}

/*
  append_vectors_once_trivial
  left_index_trivial
  left_index_with_equalizer
*/
<|endoftext|>


<commit_before>//! SSS provides Shamir's secret sharing with raw data.

use rand::{OsRng, Rng};
use merkle_sigs::sign_data_vec;

use errors::*;
use sss::{Share, HASH_ALGO};
use sss::format::format_share_for_signing;
use share::validation::{validate_share_count, validate_signed_shares};
use lagrange::interpolate_at;

use super::encode::encode_secret_byte;

/// SSS provides Shamir's secret sharing with raw data.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct SSS;

impl SSS {
    /// Performs threshold k-out-of-n Shamir's secret sharing.
    pub fn split_secret(
        &self,
        threshold: u8,
        shares_count: u8,
        secret: &[u8],
        sign_shares: bool,
    ) -> Result<Vec<Share>> {
        let (threshold, shares_count) = validate_share_count(threshold, shares_count)?;
        let shares = Self::secret_share(secret, threshold, shares_count)?;

        let signatures = if sign_shares {
            let shares_to_sign = shares
                .iter()
                .enumerate()
                .map(|(i, x)| format_share_for_signing(threshold, (i + 1) as u8, x))
                .collect::<Vec<_>>();

            let sign = sign_data_vec(&shares_to_sign, HASH_ALGO)
                .unwrap()
                .into_iter()
                .map(Some)
                .collect::<Vec<_>>();

            Some(sign)
        } else {
            None
        };

        let sig_pairs = signatures
            .unwrap_or_else(|| vec![None; shares_count as usize])
            .into_iter()
            .map(|sig_pair| sig_pair.map(From::from));

        let shares_and_sigs = shares.into_iter().enumerate().zip(sig_pairs);

        let result = shares_and_sigs.map(|((index, data), signature_pair)| {
            // This is actually safe since we alwaays generate less than 256 shares.
            let id = (index + 1) as u8;

            Share {
                id,
                threshold,
                data,
                signature_pair,
            }
        });

        Ok(result.collect())
    }

    fn secret_share(src: &[u8], threshold: u8, shares_count: u8) -> Result<Vec<Vec<u8>>> {
        let mut result = Vec::with_capacity(shares_count as usize);
        for _ in 0..(shares_count as usize) {
            result.push(vec![0u8; src.len()]);
        }
        let mut col_in = vec![0u8; threshold as usize];
        let mut col_out = Vec::with_capacity(shares_count as usize);
        let mut osrng = OsRng::new()?;
        for (c, &s) in src.iter().enumerate() {
            col_in[0] = s;
            osrng.fill_bytes(&mut col_in[1..]);
            col_out.clear();
            encode_secret_byte(&*col_in, shares_count, &mut col_out)?;
            for (&y, share) in col_out.iter().zip(result.iter_mut()) {
                share[c] = y;
            }
        }
        Ok(result)
    }

    /// Recovers the secret from a k-out-of-n Shamir's secret sharing.
    ///
    /// At least `k` distinct shares need to be provided to recover the share.
    pub fn recover_secret(shares: Vec<Share>, verify_signatures: bool) -> Result<Vec<u8>> {
        let (threshold, shares) = validate_signed_shares(shares, verify_signatures)?;

        let slen = shares[0].data.len();
        let mut col_in = Vec::with_capacity(threshold as usize);
        let mut secret = Vec::with_capacity(slen);
        for byteindex in 0..slen {
            col_in.clear();
            for s in shares.iter().take(threshold as usize) {
                col_in.push((s.id, s.data[byteindex]));
            }
            secret.push(interpolate_at(threshold, &*col_in));
        }

        Ok(secret)
    }
}
<commit_msg>Add TODO note on unreleased Rng::try_fill_bytes<commit_after>//! SSS provides Shamir's secret sharing with raw data.

use rand::{OsRng, Rng};
use merkle_sigs::sign_data_vec;

use errors::*;
use sss::{Share, HASH_ALGO};
use sss::format::format_share_for_signing;
use share::validation::{validate_share_count, validate_signed_shares};
use lagrange::interpolate_at;

use super::encode::encode_secret_byte;

/// SSS provides Shamir's secret sharing with raw data.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct SSS;

impl SSS {
    /// Performs threshold k-out-of-n Shamir's secret sharing.
    pub fn split_secret(
        &self,
        threshold: u8,
        shares_count: u8,
        secret: &[u8],
        sign_shares: bool,
    ) -> Result<Vec<Share>> {
        let (threshold, shares_count) = validate_share_count(threshold, shares_count)?;
        let shares = Self::secret_share(secret, threshold, shares_count)?;

        let signatures = if sign_shares {
            let shares_to_sign = shares
                .iter()
                .enumerate()
                .map(|(i, x)| format_share_for_signing(threshold, (i + 1) as u8, x))
                .collect::<Vec<_>>();

            let sign = sign_data_vec(&shares_to_sign, HASH_ALGO)
                .unwrap()
                .into_iter()
                .map(Some)
                .collect::<Vec<_>>();

            Some(sign)
        } else {
            None
        };

        let sig_pairs = signatures
            .unwrap_or_else(|| vec![None; shares_count as usize])
            .into_iter()
            .map(|sig_pair| sig_pair.map(From::from));

        let shares_and_sigs = shares.into_iter().enumerate().zip(sig_pairs);

        let result = shares_and_sigs.map(|((index, data), signature_pair)| {
            // This is actually safe since we alwaays generate less than 256 shares.
            let id = (index + 1) as u8;

            Share {
                id,
                threshold,
                data,
                signature_pair,
            }
        });

        Ok(result.collect())
    }

    fn secret_share(src: &[u8], threshold: u8, shares_count: u8) -> Result<Vec<Vec<u8>>> {
        let mut result = Vec::with_capacity(shares_count as usize);
        for _ in 0..(shares_count as usize) {
            result.push(vec![0u8; src.len()]);
        }
        let mut col_in = vec![0u8; threshold as usize];
        let mut col_out = Vec::with_capacity(shares_count as usize);
        let mut osrng = OsRng::new()?;
        for (c, &s) in src.iter().enumerate() {
            col_in[0] = s;
            // NOTE: switch to `try_fill_bytes` when it lands in a stable release:
            // https://github.com/rust-lang-nursery/rand/commit/230b2258dbd99ff8bd991008c972d923d4b5d10c
            osrng.fill_bytes(&mut col_in[1..]);
            col_out.clear();
            encode_secret_byte(&*col_in, shares_count, &mut col_out)?;
            for (&y, share) in col_out.iter().zip(result.iter_mut()) {
                share[c] = y;
            }
        }
        Ok(result)
    }

    /// Recovers the secret from a k-out-of-n Shamir's secret sharing.
    ///
    /// At least `k` distinct shares need to be provided to recover the share.
    pub fn recover_secret(shares: Vec<Share>, verify_signatures: bool) -> Result<Vec<u8>> {
        let (threshold, shares) = validate_signed_shares(shares, verify_signatures)?;

        let slen = shares[0].data.len();
        let mut col_in = Vec::with_capacity(threshold as usize);
        let mut secret = Vec::with_capacity(slen);
        for byteindex in 0..slen {
            col_in.clear();
            for s in shares.iter().take(threshold as usize) {
                col_in.push((s.id, s.data[byteindex]));
            }
            secret.push(interpolate_at(threshold, &*col_in));
        }

        Ok(secret)
    }
}
<|endoftext|>