<commit_before>// Copyright 2012 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.

/*!
Pulls a brief description out of a long description.

If the first paragraph of a long description is short enough then it
is interpreted as the brief description.
*/

use core::prelude::*;

use astsrv;
use doc::ItemUtils;
use doc;
use fold::Fold;
use fold;
use pass::Pass;

use core::str;
use core::vec;
use core::util;

pub fn mk_pass() -> Pass {
    Pass {
        name: ~"desc_to_brief",
        f: run
    }
}

pub fn run(
    _srv: astsrv::Srv,
    doc: doc::Doc
) -> doc::Doc {
    let fold = Fold {
        fold_item: fold_item,
        fold_trait: fold_trait,
        fold_impl: fold_impl,
        .. fold::default_any_fold(())
    };
    (fold.fold_doc)(&fold, doc)
}

fn fold_item(fold: &fold::Fold<()>, doc: doc::ItemDoc) -> doc::ItemDoc {
    let doc = fold::default_seq_fold_item(fold, doc);

    doc::ItemDoc {
        brief: extract(copy doc.desc),
        .. doc
    }
}

fn fold_trait(fold: &fold::Fold<()>, doc: doc::TraitDoc) -> doc::TraitDoc {
    let doc =fold::default_seq_fold_trait(fold, doc);

    doc::TraitDoc {
        methods: doc.methods.map(|doc| doc::MethodDoc {
            brief: extract(copy doc.desc),
            .. copy *doc
        }),
        .. doc
    }
}

fn fold_impl(fold: &fold::Fold<()>, doc: doc::ImplDoc) -> doc::ImplDoc {
    let doc =fold::default_seq_fold_impl(fold, doc);

    doc::ImplDoc {
        methods: doc.methods.map(|doc| doc::MethodDoc {
            brief: extract(copy doc.desc),
            .. copy *doc
        }),
        .. doc
    }
}

#[test]
fn should_promote_desc() {
    let doc = test::mk_doc(~"#[doc = \"desc\"] mod m { }");
    assert doc.cratemod().mods()[0].brief() == Some(~"desc");
}

#[test]
fn should_promote_trait_method_desc() {
    let doc = test::mk_doc(~"trait i { #[doc = \"desc\"] fn a(); }");
    assert doc.cratemod().traits()[0].methods[0].brief == Some(~"desc");
}

#[test]
fn should_promote_impl_method_desc() {
    let doc = test::mk_doc(
        ~"impl int { #[doc = \"desc\"] fn a() { } }");
    assert doc.cratemod().impls()[0].methods[0].brief == Some(~"desc");
}

#[cfg(test)]
pub mod test {
    use astsrv;
    use attr_pass;
    use desc_to_brief_pass::run;
    use doc;
    use extract;

    pub fn mk_doc(source: ~str) -> doc::Doc {
        do astsrv::from_str(copy source) |srv| {
            let doc = extract::from_srv(srv.clone(), ~"");
            let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
            run(srv.clone(), doc)
        }
    }
}

fn extract(desc: Option<~str>) -> Option<~str> {
    if desc.is_none() {
        return None
    }

    parse_desc((copy desc).get())
}

fn parse_desc(desc: ~str) -> Option<~str> {

    const max_brief_len: uint = 120u;

    match first_sentence(copy desc) {
      Some(first_sentence) => {
        if str::len(first_sentence) <= max_brief_len {
            Some(first_sentence)
        } else {
            None
        }
      }
      None => None
    }
}

fn first_sentence(s: ~str) -> Option<~str> {
    let paras = paragraphs(copy s);
    if !paras.is_empty() {
        let first_para = vec::head(paras);
        Some(str::replace(first_sentence_(first_para), ~"\n", ~" "))
    } else {
        None
    }
}

fn first_sentence_(s: ~str) -> ~str {
    let mut dotcount = 0;
    // The index of the character following a single dot. This allows
    // Things like [0..1) to appear in the brief description
    let idx = do str::find(s) |ch| {
        if ch == '.' {
            dotcount += 1;
            false
        } else {
            if dotcount == 1 {
                true
            } else {
                dotcount = 0;
                false
            }
        }
    };
    match idx {
      Some(idx) if idx > 2u => {
        str::slice(s, 0u, idx - 1u)
      }
      _ => {
        if str::ends_with(s, ~".") {
            str::slice(s, 0u, str::len(s))
        } else {
            copy s
        }
      }
    }
}

fn paragraphs(s: ~str) -> ~[~str] {
    let lines = str::lines_any(s);
    let mut whitespace_lines = 0;
    let mut accum = ~"";
    let paras = do vec::foldl(~[], lines) |paras, line| {
        let mut res = paras;

        if str::is_whitespace(*line) {
            whitespace_lines += 1;
        } else {
            if whitespace_lines > 0 {
                if !accum.is_empty() {
                    let v = util::replace(&mut accum, ~"");
                    res.push(v);
                }
            }

            whitespace_lines = 0;

            accum = if str::is_empty(accum) {
                copy *line
            } else {
                accum + ~"\n" + *line
            }
        }

        res
    };

    if !accum.is_empty() {
        paras + ~[accum]
    } else {
        paras
    }
}

#[test]
fn test_paragraphs_1() {
    let paras = paragraphs(~"1\n\n2");
    assert paras == ~[~"1", ~"2"];
}

#[test]
fn test_paragraphs_2() {
    let paras = paragraphs(~"\n\n1\n1\n\n2\n\n");
    assert paras == ~[~"1\n1", ~"2"];
}

#[test]
fn should_promote_short_descs() {
    let desc = Some(~"desc");
    let brief = extract(copy desc);
    assert brief == desc;
}

#[test]
fn should_not_promote_long_descs() {
    let desc = Some(~"Warkworth Castle is a ruined medieval building
in the town of the same name in the English county of Northumberland,
and the town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
    let brief = extract(desc);
    assert brief == None;
}

#[test]
fn should_promote_first_sentence() {
    let desc = Some(~"Warkworth Castle is a ruined medieval building
in the town. of the same name in the English county of Northumberland,
and the town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
    let brief = extract(desc);
    assert brief == Some(
        ~"Warkworth Castle is a ruined medieval building in the town");
}

#[test]
fn should_not_consider_double_period_to_end_sentence() {
    let desc = Some(~"Warkworth..Castle is a ruined medieval building
in the town. of the same name in the English county of Northumberland,
and the town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
    let brief = extract(desc);
    assert brief == Some(
        ~"Warkworth..Castle is a ruined medieval building in the town");
}

#[test]
fn should_not_consider_triple_period_to_end_sentence() {
    let desc = Some(~"Warkworth... Castle is a ruined medieval building
in the town. of the same name in the English county of Northumberland,
and the town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
    let brief = extract(desc);
    assert brief == Some(
        ~"Warkworth... Castle is a ruined medieval building in the town");
}
<commit_msg>rustdoc: change paragraphs fn to take &str<commit_after>// Copyright 2012 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.

/*!
Pulls a brief description out of a long description.

If the first paragraph of a long description is short enough then it
is interpreted as the brief description.
*/

use core::prelude::*;

use astsrv;
use doc::ItemUtils;
use doc;
use fold::Fold;
use fold;
use pass::Pass;

use core::str;
use core::vec;
use core::util;

pub fn mk_pass() -> Pass {
    Pass {
        name: ~"desc_to_brief",
        f: run
    }
}

pub fn run(
    _srv: astsrv::Srv,
    doc: doc::Doc
) -> doc::Doc {
    let fold = Fold {
        fold_item: fold_item,
        fold_trait: fold_trait,
        fold_impl: fold_impl,
        .. fold::default_any_fold(())
    };
    (fold.fold_doc)(&fold, doc)
}

fn fold_item(fold: &fold::Fold<()>, doc: doc::ItemDoc) -> doc::ItemDoc {
    let doc = fold::default_seq_fold_item(fold, doc);

    doc::ItemDoc {
        brief: extract(copy doc.desc),
        .. doc
    }
}

fn fold_trait(fold: &fold::Fold<()>, doc: doc::TraitDoc) -> doc::TraitDoc {
    let doc =fold::default_seq_fold_trait(fold, doc);

    doc::TraitDoc {
        methods: doc.methods.map(|doc| doc::MethodDoc {
            brief: extract(copy doc.desc),
            .. copy *doc
        }),
        .. doc
    }
}

fn fold_impl(fold: &fold::Fold<()>, doc: doc::ImplDoc) -> doc::ImplDoc {
    let doc =fold::default_seq_fold_impl(fold, doc);

    doc::ImplDoc {
        methods: doc.methods.map(|doc| doc::MethodDoc {
            brief: extract(copy doc.desc),
            .. copy *doc
        }),
        .. doc
    }
}

#[test]
fn should_promote_desc() {
    let doc = test::mk_doc(~"#[doc = \"desc\"] mod m { }");
    assert doc.cratemod().mods()[0].brief() == Some(~"desc");
}

#[test]
fn should_promote_trait_method_desc() {
    let doc = test::mk_doc(~"trait i { #[doc = \"desc\"] fn a(); }");
    assert doc.cratemod().traits()[0].methods[0].brief == Some(~"desc");
}

#[test]
fn should_promote_impl_method_desc() {
    let doc = test::mk_doc(
        ~"impl int { #[doc = \"desc\"] fn a() { } }");
    assert doc.cratemod().impls()[0].methods[0].brief == Some(~"desc");
}

#[cfg(test)]
pub mod test {
    use astsrv;
    use attr_pass;
    use desc_to_brief_pass::run;
    use doc;
    use extract;

    pub fn mk_doc(source: ~str) -> doc::Doc {
        do astsrv::from_str(copy source) |srv| {
            let doc = extract::from_srv(srv.clone(), ~"");
            let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
            run(srv.clone(), doc)
        }
    }
}

fn extract(desc: Option<~str>) -> Option<~str> {
    if desc.is_none() {
        return None
    }

    parse_desc((copy desc).get())
}

fn parse_desc(desc: ~str) -> Option<~str> {

    const max_brief_len: uint = 120u;

    match first_sentence(copy desc) {
      Some(first_sentence) => {
        if str::len(first_sentence) <= max_brief_len {
            Some(first_sentence)
        } else {
            None
        }
      }
      None => None
    }
}

fn first_sentence(s: ~str) -> Option<~str> {
    let paras = paragraphs(s);
    if !paras.is_empty() {
        let first_para = vec::head(paras);
        Some(str::replace(first_sentence_(first_para), ~"\n", ~" "))
    } else {
        None
    }
}

fn first_sentence_(s: ~str) -> ~str {
    let mut dotcount = 0;
    // The index of the character following a single dot. This allows
    // Things like [0..1) to appear in the brief description
    let idx = do str::find(s) |ch| {
        if ch == '.' {
            dotcount += 1;
            false
        } else {
            if dotcount == 1 {
                true
            } else {
                dotcount = 0;
                false
            }
        }
    };
    match idx {
      Some(idx) if idx > 2u => {
        str::slice(s, 0u, idx - 1u)
      }
      _ => {
        if str::ends_with(s, ~".") {
            str::slice(s, 0u, str::len(s))
        } else {
            copy s
        }
      }
    }
}

fn paragraphs(s: &str) -> ~[~str] {
    let lines = str::lines_any(s);
    let mut whitespace_lines = 0;
    let mut accum = ~"";
    let paras = do vec::foldl(~[], lines) |paras, line| {
        let mut res = paras;

        if str::is_whitespace(*line) {
            whitespace_lines += 1;
        } else {
            if whitespace_lines > 0 {
                if !accum.is_empty() {
                    let v = util::replace(&mut accum, ~"");
                    res.push(v);
                }
            }

            whitespace_lines = 0;

            accum = if str::is_empty(accum) {
                copy *line
            } else {
                accum + ~"\n" + *line
            }
        }

        res
    };

    if !accum.is_empty() {
        paras + ~[accum]
    } else {
        paras
    }
}

#[test]
fn test_paragraphs_1() {
    let paras = paragraphs(~"1\n\n2");
    assert paras == ~[~"1", ~"2"];
}

#[test]
fn test_paragraphs_2() {
    let paras = paragraphs(~"\n\n1\n1\n\n2\n\n");
    assert paras == ~[~"1\n1", ~"2"];
}

#[test]
fn should_promote_short_descs() {
    let desc = Some(~"desc");
    let brief = extract(copy desc);
    assert brief == desc;
}

#[test]
fn should_not_promote_long_descs() {
    let desc = Some(~"Warkworth Castle is a ruined medieval building
in the town of the same name in the English county of Northumberland,
and the town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
    let brief = extract(desc);
    assert brief == None;
}

#[test]
fn should_promote_first_sentence() {
    let desc = Some(~"Warkworth Castle is a ruined medieval building
in the town. of the same name in the English county of Northumberland,
and the town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
    let brief = extract(desc);
    assert brief == Some(
        ~"Warkworth Castle is a ruined medieval building in the town");
}

#[test]
fn should_not_consider_double_period_to_end_sentence() {
    let desc = Some(~"Warkworth..Castle is a ruined medieval building
in the town. of the same name in the English county of Northumberland,
and the town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
    let brief = extract(desc);
    assert brief == Some(
        ~"Warkworth..Castle is a ruined medieval building in the town");
}

#[test]
fn should_not_consider_triple_period_to_end_sentence() {
    let desc = Some(~"Warkworth... Castle is a ruined medieval building
in the town. of the same name in the English county of Northumberland,
and the town and castle occupy a loop of the River Coquet, less than a mile
from England's north-east coast. When the castle was founded is uncertain,
but traditionally its construction has been ascribed to Prince Henry of
Scotland in the mid 12th century, although it may have been built by
King Henry II of England when he took control of England'snorthern
counties.");
    let brief = extract(desc);
    assert brief == Some(
        ~"Warkworth... Castle is a ruined medieval building in the town");
}
<|endoftext|>


<commit_before>use egui::{
    plot::{Bar, BarChart, HLine, Line, Plot, Value, Values},
    Color32, Context, Grid, Ui, Visuals,
};
use gba::{Command, Gba, GbaAudioSampler};
use parking_lot::Mutex;
use pyrite::{CallbackId, GbaHandle, GbaThreadState};
use std::{sync::Arc, time::Duration};
use util::circular::CircularBuffer;

#[derive(Default)]
pub struct Debugger {
    current_pane: Pane,
    performance_pane: PerformancePane,
    audio_pane: AudioPane,

    has_initialized: bool,

    gba_data: GbaData,
    gba_data_buffer: Arc<Mutex<GbaData>>,
    frame_callback: Option<CallbackId>,
}

impl Debugger {
    pub fn render(&mut self, ctx: &Context, gba: &GbaHandle) {
        if !self.has_initialized {
            self.init(ctx, gba);
            self.has_initialized = true;
        } else {
            self.fetch_updated_data();

            if self.gba_data.updated {
                ctx.request_repaint();
            }
        }

        egui::CentralPanel::default().show(ctx, |ui| {
            ui.horizontal(|ui| {
                ui.selectable_value(&mut self.current_pane, Pane::Performance, "Performance");
                ui.selectable_value(&mut self.current_pane, Pane::Audio, "Audio");
            });

            match self.current_pane {
                Pane::Performance => self.performance_pane.render(ui, &mut self.gba_data),
                Pane::Audio => self.audio_pane.render(ui, &mut self.gba_data),
            }
        });
    }

    fn fetch_updated_data(&mut self) {
        let mut locked = self.gba_data_buffer.lock();
        self.gba_data.copy_data(&mut *locked);
    }

    #[cold]
    pub fn init(&mut self, ctx: &Context, gba: &GbaHandle) {
        let mut visuals = Visuals::dark();
        visuals.override_text_color = Some(Color32::from_rgb(0xe9, 0xec, 0xef));
        ctx.set_visuals(visuals);

        let gba_data_buffer = Arc::clone(&self.gba_data_buffer);
        let callback_id = gba.on_frame(move |gba, state| {
            let mut locked = gba_data_buffer.lock();
            pull_data_from_gba(&mut *locked, gba, state);
        });

        self.frame_callback = Some(callback_id);
    }

    pub fn destroy(&mut self, gba: &GbaHandle) {
        if let Some(cb) = self.frame_callback.take() {
            gba.remove_on_frame(cb);
        }
    }
}

#[derive(PartialEq, Clone, Copy)]
enum Pane {
    Performance,
    Audio,
}

impl Default for Pane {
    fn default() -> Self {
        Self::Performance
    }
}

struct AudioPane {
    sampler: GbaAudioSampler,
    samples_l: CircularBuffer<f32, { Self::BUFFER_SIZE }>,
    samples_r: CircularBuffer<f32, { Self::BUFFER_SIZE }>,
    commands_buffer_sizes: CircularBuffer<u32, { Self::FRAMES }>,
}

impl AudioPane {
    const RENDER_SAMPLES: u32 = 1024;
    const FRAMES: usize = 16;
    const BUFFER_SIZE: usize = Self::FRAMES * Self::RENDER_SAMPLES as usize;

    fn render(&mut self, ui: &mut Ui, data: &mut GbaData) {
        self.get_data(data);
        Grid::new("GBA Frame Durations Grid")
            .num_columns(2)
            .striped(true)
            .show(ui, |ui| {
                ui.label("Output");
                self.render_samples_plot(ui);
                ui.end_row();

                ui.label("Commands");
                self.render_commands_buffer_plot(ui);
                ui.end_row();
            });
    }

    fn render_commands_buffer_plot(&mut self, ui: &mut Ui) {
        let mut bars = Vec::with_capacity(self.commands_buffer_sizes.len());
        for (idx, &size) in self.commands_buffer_sizes.iter().enumerate() {
            bars.push(Bar::new(idx as f64, size as f64));
        }

        let chart = BarChart::new(bars).name("Command Buffer Size Chart");
        Plot::new("Command Buffer Sizes")
            .allow_drag(false)
            .allow_zoom(false)
            .show(ui, |plot_ui| {
                plot_ui.bar_chart(chart);
            });
    }

    fn render_samples_plot(&mut self, ui: &mut Ui) {
        let samples_l = self
            .samples_l
            .iter()
            .enumerate()
            .map(|(idx, &s)| Value::new(idx as f64, s));
        let samples_r = self
            .samples_r
            .iter()
            .enumerate()
            .map(|(idx, &s)| Value::new(idx as f64, s));

        let line_l = Line::new(Values::from_values_iter(samples_l)).color(rgb(0x228be6));
        let line_r = Line::new(Values::from_values_iter(samples_r)).color(rgb(0xae3ec9));

        Plot::new("Samples")
            .show_axes([false, false])
            .allow_drag(true)
            .allow_zoom(true)
            .include_y(1.0)
            .include_y(-1.0)
            .show(ui, |plot_ui| {
                plot_ui.line(line_l);
                plot_ui.line(line_r);
            });
    }

    fn get_data(&mut self, data: &mut GbaData) {
        if std::mem::take(&mut data.has_audio_commands) {
            self.commands_buffer_sizes
                .push(data.audio_commands.len() as u32);
            for _ in 0..Self::RENDER_SAMPLES {
                while self.sampler.needs_commands() {
                    if let Some(command) = data.audio_commands.pop() {
                        self.sampler.command(command);
                    } else {
                        break;
                    }
                }

                let (l, r) = self.sampler.frame();
                self.samples_l.push(l);
                self.samples_r.push(r);
            }
        }
        data.requests.audio_data = true;
    }
}

impl Default for AudioPane {
    fn default() -> Self {
        AudioPane {
            sampler: GbaAudioSampler::new(Self::RENDER_SAMPLES),
            samples_l: Default::default(),
            samples_r: Default::default(),
            commands_buffer_sizes: Default::default(),
        }
    }
}

#[derive(Default)]
struct PerformancePane {
    frame_times: CircularBuffer<f64, 32>,
    frame_processing_times: CircularBuffer<f64, 32>,
}

impl PerformancePane {
    const GBA_MAX_FRAME_DUR: f64 = 1000.0 / 60.0;

    const GOOD_FRAME_COLOR: Color32 = Color32::from_rgb(0x37, 0xb2, 0x4d);
    const BAD_FRAME_COLOR: Color32 = Color32::from_rgb(0xf0, 0x3e, 0x3e);

    fn render(&mut self, ui: &mut Ui, data: &mut GbaData) {
        if let Some(duration) = data.frame_duration.take() {
            self.frame_times.push(duration.as_secs_f64() * 1000.0);
        }

        if let Some(duration) = data.frame_processing_duration.take() {
            self.frame_processing_times
                .push(duration.as_secs_f64() * 1000.0);
        }

        self.render_frame_times(ui);
        data.requests.frame_duration = true;
    }

    fn render_frame_times_text(&mut self, ui: &mut Ui) {
        let average_dur =
            self.frame_times.iter().copied().sum::<f64>() / self.frame_times.len() as f64;
        ui.label("Average GBA Frame Duration");
        ui.label(format!("{average_dur:0.2}ms"));
        ui.end_row();

        let average_fps = 1000.0 / average_dur;
        ui.label("Average GBA FPS");
        ui.label(format!("{average_fps:0.2}"));
        ui.end_row();

        let average_perf = (Self::GBA_MAX_FRAME_DUR / average_dur) * 100.0;
        ui.label("Average GBA Performance");
        ui.label(format!("{average_perf:0.2}%"));
        ui.end_row();
    }

    fn render_processing_times_plot(&mut self, ui: &mut Ui) {
        const PROCESSING_COLOR: Color32 = Color32::from_rgb(0x1c, 0x7e, 0xd6);
        let mut bars = Vec::with_capacity(self.frame_processing_times.len());
        for (idx, &t) in self.frame_processing_times.iter().skip(1).enumerate() {
            bars.push(Bar::new(idx as f64, t).fill(PROCESSING_COLOR));
        }

        if !self.frame_processing_times.is_empty() {
            bars.push(Bar::new(bars.len() as f64, 0.0));
        }

        let chart = BarChart::new(bars).name("GBA Frame Processing Duration");
        Plot::new("GBA Processing Durations")
            .show_x(false)
            .show_axes([false, false])
            .allow_drag(false)
            .allow_zoom(false)
            .include_y(Self::GBA_MAX_FRAME_DUR)
            .show(ui, |plot_ui| {
                plot_ui.bar_chart(chart);
            });
    }

    fn render_frame_times_plot(&mut self, ui: &mut Ui) {
        let bar_color = |t: f64| -> Color32 {
            if t > 4.0 {
                Self::BAD_FRAME_COLOR
            } else {
                Self::GOOD_FRAME_COLOR
            }
        };

        let bars = self
            .frame_times
            .iter()
            .enumerate()
            .map(|(idx, &t)| Bar::new(idx as f64, t).fill(bar_color(t)))
            .collect();
        let chart = BarChart::new(bars).name("GBA Frame Processing Duration");
        Plot::new("GBA Frame Durations")
            .show_x(false)
            .show_axes([false, false])
            .allow_drag(false)
            .allow_zoom(false)
            .include_y(Self::GBA_MAX_FRAME_DUR)
            .show(ui, |plot_ui| {
                plot_ui.hline(HLine::new(4.0).color(Self::BAD_FRAME_COLOR));
                plot_ui.bar_chart(chart);
            });
    }

    fn render_frame_times(&mut self, ui: &mut Ui) {
        Grid::new("GBA Frame Durations Grid")
            .num_columns(2)
            .striped(true)
            .show(ui, |ui| {
                self.render_frame_times_text(ui);

                ui.label("GBA Frame Durations");
                self.render_frame_times_plot(ui);
                ui.end_row();

                ui.label("GBA Processing Durations");
                self.render_processing_times_plot(ui);
                ui.end_row();
            });
    }
}

#[derive(Default)]
struct GbaData {
    frame_duration: Option<Duration>,
    frame_processing_duration: Option<Duration>,

    audio_commands: Vec<Command>,
    has_audio_commands: bool,

    updated: bool,
    requests: GbaDataRequests,
}

impl GbaData {
    fn copy_data(&mut self, source: &mut GbaData) {
        if !source.updated {
            self.updated = false;
            return;
        }
        self.updated = true;
        source.updated = false;

        self.frame_duration = source.frame_duration.take();
        self.frame_processing_duration = source.frame_processing_duration.take();

        if self.requests.audio_data {
            self.audio_commands.clear();
            self.audio_commands
                .extend(source.audio_commands.iter().rev().copied());
            self.has_audio_commands = source.has_audio_commands;
        } else {
            self.has_audio_commands = false;
        }

        source.requests = std::mem::take(&mut self.requests);
    }
}

#[derive(Default)]
struct GbaDataRequests {
    frame_duration: bool,
    audio_data: bool,
}

fn pull_data_from_gba(data: &mut GbaData, gba: &mut Gba, state: &mut GbaThreadState) {
    if data.requests.frame_duration {
        data.frame_duration = Some(state.frame_duration());
        data.frame_processing_duration = Some(state.frame_processing_duration());
    }

    if data.requests.audio_data {
        data.audio_commands.clear();
        data.audio_commands.extend(gba.audio().commands());
        data.has_audio_commands = true;
    } else {
        data.has_audio_commands = false;
    }

    data.updated = true;
}

const fn rgb(col: u32) -> Color32 {
    Color32::from_rgb((col >> 16) as u8, (col >> 8) as u8, col as u8)
}
<commit_msg>Allow zooming command buffer size graph in debugger.<commit_after>use egui::{
    plot::{Bar, BarChart, HLine, Line, Plot, Value, Values},
    Color32, Context, Grid, Ui, Visuals,
};
use gba::{Command, Gba, GbaAudioSampler};
use parking_lot::Mutex;
use pyrite::{CallbackId, GbaHandle, GbaThreadState};
use std::{sync::Arc, time::Duration};
use util::circular::CircularBuffer;

#[derive(Default)]
pub struct Debugger {
    current_pane: Pane,
    performance_pane: PerformancePane,
    audio_pane: AudioPane,

    has_initialized: bool,

    gba_data: GbaData,
    gba_data_buffer: Arc<Mutex<GbaData>>,
    frame_callback: Option<CallbackId>,
}

impl Debugger {
    pub fn render(&mut self, ctx: &Context, gba: &GbaHandle) {
        if !self.has_initialized {
            self.init(ctx, gba);
            self.has_initialized = true;
        } else {
            self.fetch_updated_data();

            if self.gba_data.updated {
                ctx.request_repaint();
            }
        }

        egui::CentralPanel::default().show(ctx, |ui| {
            ui.horizontal(|ui| {
                ui.selectable_value(&mut self.current_pane, Pane::Performance, "Performance");
                ui.selectable_value(&mut self.current_pane, Pane::Audio, "Audio");
            });

            match self.current_pane {
                Pane::Performance => self.performance_pane.render(ui, &mut self.gba_data),
                Pane::Audio => self.audio_pane.render(ui, &mut self.gba_data),
            }
        });
    }

    fn fetch_updated_data(&mut self) {
        let mut locked = self.gba_data_buffer.lock();
        self.gba_data.copy_data(&mut *locked);
    }

    #[cold]
    pub fn init(&mut self, ctx: &Context, gba: &GbaHandle) {
        let mut visuals = Visuals::dark();
        visuals.override_text_color = Some(Color32::from_rgb(0xe9, 0xec, 0xef));
        ctx.set_visuals(visuals);

        let gba_data_buffer = Arc::clone(&self.gba_data_buffer);
        let callback_id = gba.on_frame(move |gba, state| {
            let mut locked = gba_data_buffer.lock();
            pull_data_from_gba(&mut *locked, gba, state);
        });

        self.frame_callback = Some(callback_id);
    }

    pub fn destroy(&mut self, gba: &GbaHandle) {
        if let Some(cb) = self.frame_callback.take() {
            gba.remove_on_frame(cb);
        }
    }
}

#[derive(PartialEq, Clone, Copy)]
enum Pane {
    Performance,
    Audio,
}

impl Default for Pane {
    fn default() -> Self {
        Self::Performance
    }
}

struct AudioPane {
    sampler: GbaAudioSampler,
    samples_l: CircularBuffer<f32, { Self::BUFFER_SIZE }>,
    samples_r: CircularBuffer<f32, { Self::BUFFER_SIZE }>,
    commands_buffer_sizes: CircularBuffer<u32, { Self::FRAMES }>,
}

impl AudioPane {
    const RENDER_SAMPLES: u32 = 1024;
    const FRAMES: usize = 16;
    const BUFFER_SIZE: usize = Self::FRAMES * Self::RENDER_SAMPLES as usize;

    fn render(&mut self, ui: &mut Ui, data: &mut GbaData) {
        self.get_data(data);
        Grid::new("GBA Frame Durations Grid")
            .num_columns(2)
            .striped(true)
            .show(ui, |ui| {
                ui.label("Output");
                self.render_samples_plot(ui);
                ui.end_row();

                ui.label("Commands");
                self.render_commands_buffer_plot(ui);
                ui.end_row();
            });
    }

    fn render_commands_buffer_plot(&mut self, ui: &mut Ui) {
        let mut bars = Vec::with_capacity(self.commands_buffer_sizes.len());
        for (idx, &size) in self.commands_buffer_sizes.iter().enumerate() {
            bars.push(Bar::new(idx as f64, size as f64));
        }

        let chart = BarChart::new(bars).name("Command Buffer Size Chart");
        Plot::new("Command Buffer Sizes")
            .allow_drag(false)
            .allow_zoom(true)
            .show(ui, |plot_ui| {
                plot_ui.bar_chart(chart);
            });
    }

    fn render_samples_plot(&mut self, ui: &mut Ui) {
        let samples_l = self
            .samples_l
            .iter()
            .enumerate()
            .map(|(idx, &s)| Value::new(idx as f64, s));
        let samples_r = self
            .samples_r
            .iter()
            .enumerate()
            .map(|(idx, &s)| Value::new(idx as f64, s));

        let line_l = Line::new(Values::from_values_iter(samples_l)).color(rgb(0x228be6));
        let line_r = Line::new(Values::from_values_iter(samples_r)).color(rgb(0xae3ec9));

        Plot::new("Samples")
            .show_axes([false, false])
            .allow_drag(true)
            .allow_zoom(true)
            .include_y(1.0)
            .include_y(-1.0)
            .show(ui, |plot_ui| {
                plot_ui.line(line_l);
                plot_ui.line(line_r);
            });
    }

    fn get_data(&mut self, data: &mut GbaData) {
        if std::mem::take(&mut data.has_audio_commands) {
            self.commands_buffer_sizes
                .push(data.audio_commands.len() as u32);
            for _ in 0..Self::RENDER_SAMPLES {
                while self.sampler.needs_commands() {
                    if let Some(command) = data.audio_commands.pop() {
                        self.sampler.command(command);
                    } else {
                        break;
                    }
                }

                let (l, r) = self.sampler.frame();
                self.samples_l.push(l);
                self.samples_r.push(r);
            }
        }
        data.requests.audio_data = true;
    }
}

impl Default for AudioPane {
    fn default() -> Self {
        AudioPane {
            sampler: GbaAudioSampler::new(Self::RENDER_SAMPLES),
            samples_l: Default::default(),
            samples_r: Default::default(),
            commands_buffer_sizes: Default::default(),
        }
    }
}

#[derive(Default)]
struct PerformancePane {
    frame_times: CircularBuffer<f64, 32>,
    frame_processing_times: CircularBuffer<f64, 32>,
}

impl PerformancePane {
    const GBA_MAX_FRAME_DUR: f64 = 1000.0 / 60.0;

    const GOOD_FRAME_COLOR: Color32 = Color32::from_rgb(0x37, 0xb2, 0x4d);
    const BAD_FRAME_COLOR: Color32 = Color32::from_rgb(0xf0, 0x3e, 0x3e);

    fn render(&mut self, ui: &mut Ui, data: &mut GbaData) {
        if let Some(duration) = data.frame_duration.take() {
            self.frame_times.push(duration.as_secs_f64() * 1000.0);
        }

        if let Some(duration) = data.frame_processing_duration.take() {
            self.frame_processing_times
                .push(duration.as_secs_f64() * 1000.0);
        }

        self.render_frame_times(ui);
        data.requests.frame_duration = true;
    }

    fn render_frame_times_text(&mut self, ui: &mut Ui) {
        let average_dur =
            self.frame_times.iter().copied().sum::<f64>() / self.frame_times.len() as f64;
        ui.label("Average GBA Frame Duration");
        ui.label(format!("{average_dur:0.2}ms"));
        ui.end_row();

        let average_fps = 1000.0 / average_dur;
        ui.label("Average GBA FPS");
        ui.label(format!("{average_fps:0.2}"));
        ui.end_row();

        let average_perf = (Self::GBA_MAX_FRAME_DUR / average_dur) * 100.0;
        ui.label("Average GBA Performance");
        ui.label(format!("{average_perf:0.2}%"));
        ui.end_row();
    }

    fn render_processing_times_plot(&mut self, ui: &mut Ui) {
        const PROCESSING_COLOR: Color32 = Color32::from_rgb(0x1c, 0x7e, 0xd6);
        let mut bars = Vec::with_capacity(self.frame_processing_times.len());
        for (idx, &t) in self.frame_processing_times.iter().skip(1).enumerate() {
            bars.push(Bar::new(idx as f64, t).fill(PROCESSING_COLOR));
        }

        if !self.frame_processing_times.is_empty() {
            bars.push(Bar::new(bars.len() as f64, 0.0));
        }

        let chart = BarChart::new(bars).name("GBA Frame Processing Duration");
        Plot::new("GBA Processing Durations")
            .show_x(false)
            .show_axes([false, false])
            .allow_drag(false)
            .allow_zoom(false)
            .include_y(Self::GBA_MAX_FRAME_DUR)
            .show(ui, |plot_ui| {
                plot_ui.bar_chart(chart);
            });
    }

    fn render_frame_times_plot(&mut self, ui: &mut Ui) {
        let bar_color = |t: f64| -> Color32 {
            if t > 4.0 {
                Self::BAD_FRAME_COLOR
            } else {
                Self::GOOD_FRAME_COLOR
            }
        };

        let bars = self
            .frame_times
            .iter()
            .enumerate()
            .map(|(idx, &t)| Bar::new(idx as f64, t).fill(bar_color(t)))
            .collect();
        let chart = BarChart::new(bars).name("GBA Frame Processing Duration");
        Plot::new("GBA Frame Durations")
            .show_x(false)
            .show_axes([false, false])
            .allow_drag(false)
            .allow_zoom(false)
            .include_y(Self::GBA_MAX_FRAME_DUR)
            .show(ui, |plot_ui| {
                plot_ui.hline(HLine::new(4.0).color(Self::BAD_FRAME_COLOR));
                plot_ui.bar_chart(chart);
            });
    }

    fn render_frame_times(&mut self, ui: &mut Ui) {
        Grid::new("GBA Frame Durations Grid")
            .num_columns(2)
            .striped(true)
            .show(ui, |ui| {
                self.render_frame_times_text(ui);

                ui.label("GBA Frame Durations");
                self.render_frame_times_plot(ui);
                ui.end_row();

                ui.label("GBA Processing Durations");
                self.render_processing_times_plot(ui);
                ui.end_row();
            });
    }
}

#[derive(Default)]
struct GbaData {
    frame_duration: Option<Duration>,
    frame_processing_duration: Option<Duration>,

    audio_commands: Vec<Command>,
    has_audio_commands: bool,

    updated: bool,
    requests: GbaDataRequests,
}

impl GbaData {
    fn copy_data(&mut self, source: &mut GbaData) {
        if !source.updated {
            self.updated = false;
            return;
        }
        self.updated = true;
        source.updated = false;

        self.frame_duration = source.frame_duration.take();
        self.frame_processing_duration = source.frame_processing_duration.take();

        if self.requests.audio_data {
            self.audio_commands.clear();
            self.audio_commands
                .extend(source.audio_commands.iter().rev().copied());
            self.has_audio_commands = source.has_audio_commands;
        } else {
            self.has_audio_commands = false;
        }

        source.requests = std::mem::take(&mut self.requests);
    }
}

#[derive(Default)]
struct GbaDataRequests {
    frame_duration: bool,
    audio_data: bool,
}

fn pull_data_from_gba(data: &mut GbaData, gba: &mut Gba, state: &mut GbaThreadState) {
    if data.requests.frame_duration {
        data.frame_duration = Some(state.frame_duration());
        data.frame_processing_duration = Some(state.frame_processing_duration());
    }

    if data.requests.audio_data {
        data.audio_commands.clear();
        data.audio_commands.extend(gba.audio().commands());
        data.has_audio_commands = true;
    } else {
        data.has_audio_commands = false;
    }

    data.updated = true;
}

const fn rgb(col: u32) -> Color32 {
    Color32::from_rgb((col >> 16) as u8, (col >> 8) as u8, col as u8)
}
<|endoftext|>


<commit_before>fn main() {
    child_window_example::child_window();
}

#[cfg(windows)]
mod child_window_example {

    extern crate winit;
    extern crate winapi;
    use std::thread;
    use self::winit::os::windows::{WindowBuilderExt, WindowExt};

    fn resize_callback(width: u32, height: u32) {
        println!("Window resized to {}x{}", width, height);
    }
    /**
    * Creates a main window and a child within it and handle their events separetely.
    * Currently windows only
    */
    pub fn child_window() {
        let window = winit::WindowBuilder::new()
            .with_title("A fantastic window!")
            .with_window_resize_callback(resize_callback)
            .build()
            .unwrap();

        let parent = window.get_hwnd() as winapi::HWND;
        let child = winit::WindowBuilder::new()
            .with_title("child window!")
            .with_window_resize_callback(resize_callback)
            .with_decorations(false)
            .with_dimensions(100, 100)
            .with_parent_window(parent)
            .build()
            .unwrap();

        let child_thread = thread::spawn(move || {
            for event in child.wait_events() {
                println!("child {:?}", event);

                match event {
                    winit::Event::Closed => break,
                    _ => (),
                }
            }
        });

        for event in window.wait_events() {
            println!("parent {:?}", event);

            match event {
                winit::Event::Closed => break,
                _ => (),
            }
        }

        child_thread.join().unwrap();
    }
}

#[cfg(not(windows))]
mod child_window_example {
    pub fn child_window() {}
}
<commit_msg>remove useless example<commit_after><|endoftext|>


<commit_before>#[cfg(feature = "ispc")]
extern crate ispc_compile;
extern crate ispc_rt;

#[cfg(feature = "ispc")]
fn link_ispc() {
    use ispc_compile::TargetISA;
    // For a portable program we can explicitly compile for each target ISA
    // we want. Then ISPC will pick the correct ISA at runtime to call
    // for the target CPU.
    ispc_compile::Config::new()
        .file("src/simple.ispc")
        .target_isas(vec![
            TargetISA::SSE2i32x4,
            TargetISA::SSE4i32x4,
            TargetISA::AVX1i32x8,
            TargetISA::AVX2i32x8,
            TargetISA::AVX512KNLi32x16,
            TargetISA::AVX512SKXi32x8,
        ])
        .out_dir("src/")
        .compile("simple");
}

#[cfg(not(feature = "ispc"))]
fn link_ispc() {
    ispc_rt::PackagedModule::new("simple")
        .lib_path("src/")
        .link();
}

fn main() {
    link_ispc();
}
<commit_msg>arm/neon support in simple example<commit_after>#[cfg(feature = "ispc")]
extern crate ispc_compile;
extern crate ispc_rt;

#[cfg(feature = "ispc")]
fn link_ispc() {
    use ispc_compile::TargetISA;

    #[cfg(target_arch = "x86_64")]
    let target_isas = vec![
        TargetISA::SSE2i32x4,
        TargetISA::SSE4i32x4,
        TargetISA::AVX1i32x8,
        TargetISA::AVX2i32x8,
        TargetISA::AVX512KNLi32x16,
        TargetISA::AVX512SKXi32x8,
    ];

    #[cfg(target_arch = "aarch64")]
    let target_isas = vec![TargetISA::Neoni32x4];

    // For a portable program we can explicitly compile for each target ISA
    // we want. Then ISPC will pick the correct ISA at runtime to call
    // for the target CPU.
    ispc_compile::Config::new()
        .file("src/simple.ispc")
        .target_isas(target_isas)
        .out_dir("src/")
        .compile("simple");
}

#[cfg(not(feature = "ispc"))]
fn link_ispc() {
    ispc_rt::PackagedModule::new("simple")
        .lib_path("src/")
        .link();
}

fn main() {
    link_ispc();
}
<|endoftext|>


<commit_before>extern crate rs_logic;

use rs_logic::element::*;

// NOT X = X NAND X
fn init_not() -> Element {
    // init hardcoded NAND component
    let nand = Element::init_nand();
    // init user NOT component (composit)
    let mut not = Element::init("NOT", 1, 1);
    // push NAND component into NOT
    let nand_id = not.push_element(nand);
    // connect all wires
    not.connect_wire(Wire::InputSelf(0), Wire::Input(nand_id, 0));
    not.connect_wire(Wire::InputSelf(0), Wire::Input(nand_id, 1));
    not.connect_wire(Wire::Output(nand_id, 0), Wire::OutputSelf(0));
    not
}

//              A     B     C
// X AND Y = (NOT X) NOR (NOT Y)
fn init_and() -> Element {
    let not_a = init_not();
    let not_b = init_not();
    let nor = Element::init_nor();
    // init user AND component
    let mut and = Element::init("AND", 2, 1);
    // push all components
    let nid = and.push_element(nor);
    let aid = and.push_element(not_a);
    let bid = and.push_element(not_b);
    // connect A
    and.connect_wire(Wire::InputSelf(0), Wire::Input(aid, 0));
    // connect C
    and.connect_wire(Wire::InputSelf(1), Wire::Input(bid, 0));
    // connect B
    and.connect_wire(Wire::Output(aid, 0), Wire::Input(nid, 0));
    and.connect_wire(Wire::Output(bid, 0), Wire::Input(nid, 1));
    // result to output
    and.connect_wire(Wire::Output(nid, 0), Wire::OutputSelf(0));
    and
}

//             A     B      C
// X OR Y = (NOT X) NAND (NOT Y)
fn init_or() -> Element {
    let not_a = init_not();
    let not_b = init_not();
    let nand = Element::init_nand();
    // init user OR component
    let mut or = Element::init("OR", 2, 1);
    // push all components
    let nid = or.push_element(nand);
    let aid = or.push_element(not_a);
    let bid = or.push_element(not_b);
    // connect A
    or.connect_wire(Wire::InputSelf(0), Wire::Input(aid, 0));
    // connect C
    or.connect_wire(Wire::InputSelf(1), Wire::Input(bid, 0));
    // connect B
    or.connect_wire(Wire::Output(aid, 0), Wire::Input(nid, 0));
    or.connect_wire(Wire::Output(bid, 0), Wire::Input(nid, 1));
    // result to output
    or.connect_wire(Wire::Output(nid, 0), Wire::OutputSelf(0));
    or
}

fn main() {
    let mut not = init_not();
    println!("NOT component:");
    for v1 in vec![0, 1] {
        not.set_input_wire(0, v1);
        not.execute();
        println!("  {:?}", not);
    }
    let mut and = init_and();
    println!("AND component:");
    for (v1, v2) in vec![(0, 0), (0, 1), (1, 0), (1, 1)] {
        and.set_input_wire(0, v1);
        and.set_input_wire(1, v2);
        and.execute();
        println!("  {:?}", and);
    }
    let mut or = init_or();
    println!("OR component:");
    for (v1, v2) in vec![(0, 0), (0, 1), (1, 0), (1, 1)] {
        or.set_input_wire(0, v1);
        or.set_input_wire(1, v2);
        or.execute();
        println!("  {:?}", or);
    }
}<commit_msg>[add] xor element and code restruct<commit_after>extern crate rs_logic;

use rs_logic::element::*;

// NOT X = X NAND X
fn init_not() -> Element {
    // init hardcoded NAND component
    let nand = Element::init_nand();
    // init user NOT component (composit)
    let mut not = Element::init("NOT", 1, 1);
    // push NAND component into NOT
    let nand_id = not.push_element(nand);
    // connect all wires
    not.connect_wire(Wire::InputSelf(0), Wire::Input(nand_id, 0));
    not.connect_wire(Wire::InputSelf(0), Wire::Input(nand_id, 1));
    not.connect_wire(Wire::Output(nand_id, 0), Wire::OutputSelf(0));
    not
}

//              A     B     C
// X AND Y = (NOT X) NOR (NOT Y)
fn init_and() -> Element {
    let not_a = init_not();
    let not_b = init_not();
    let nor = Element::init_nor();
    // init user AND component
    let mut and = Element::init("AND", 2, 1);
    // push all components
    let b = and.push_element(nor);
    let a = and.push_element(not_a);
    let c = and.push_element(not_b);
    // connect A
    and.connect_wire(Wire::InputSelf(0), Wire::Input(a, 0));
    // connect C
    and.connect_wire(Wire::InputSelf(1), Wire::Input(c, 0));
    // connect B
    and.connect_wire(Wire::Output(a, 0), Wire::Input(b, 0));
    and.connect_wire(Wire::Output(c, 0), Wire::Input(b, 1));
    // result to output
    and.connect_wire(Wire::Output(b, 0), Wire::OutputSelf(0));
    and
}

//             A     B      C
// X OR Y = (NOT X) NAND (NOT Y)
fn init_or() -> Element {
    let not_a = init_not();
    let not_b = init_not();
    let nand = Element::init_nand();
    // init user OR component
    let mut or = Element::init("OR", 2, 1);
    // push all components
    let b = or.push_element(nand);
    let a = or.push_element(not_a);
    let c = or.push_element(not_b);
    // connect A
    or.connect_wire(Wire::InputSelf(0), Wire::Input(a, 0));
    // connect C
    or.connect_wire(Wire::InputSelf(1), Wire::Input(c, 0));
    // connect B
    or.connect_wire(Wire::Output(a, 0), Wire::Input(b, 0));
    or.connect_wire(Wire::Output(c, 0), Wire::Input(b, 1));
    // result to output
    or.connect_wire(Wire::Output(b, 0), Wire::OutputSelf(0));
    or
}

// SOMETHING WENT WRONG!
//               A       B     C
// X XOR Y = (X NAND Y) AND (X OR Y)
fn init_xor() -> Element {
    let nand = Element::init_nand();
    let or = init_or();
    let and = init_and();
    // init user XOR component
    let mut xor = Element::init("XOR", 2, 1);
    // push all components
    let a = xor.push_element(nand);
    let b = xor.push_element(and);
    let c = xor.push_element(or);
    // connect A
    xor.connect_wire(Wire::InputSelf(0), Wire::Input(a, 0));
    xor.connect_wire(Wire::InputSelf(1), Wire::Input(a, 1));
    // connect C
    xor.connect_wire(Wire::InputSelf(0), Wire::Input(c, 0));
    xor.connect_wire(Wire::InputSelf(1), Wire::Input(c, 1));
    // connect B
    xor.connect_wire(Wire::Output(a, 0), Wire::Input(b, 0));
    xor.connect_wire(Wire::Output(c, 0), Wire::Input(b, 1));
    // result to output
    xor.connect_wire(Wire::Output(b, 0), Wire::OutputSelf(0));
    xor
}

fn main() {
    let mut not = init_not();
    println!("NOT component:");
    for v1 in vec![0, 1] {
        not.set_input_wire(0, v1);
        not.execute();
        println!("  [{}] -> {:?}", v1, not.get_output());
    }
    let mut and = init_and();
    let mut and_result = String::new();
    let mut or = init_or();
    let mut or_result = String::new();
    let mut xor = init_xor();
    let mut xor_result = String::new();
    for (v1, v2) in vec![(0, 0), (0, 1), (1, 0), (1, 1)] {
        and.set_input(vec![v1, v2]);
        and.execute();
        or.set_input(vec![v1, v2]);
        or.execute();
        xor.set_input(vec![v1, v2]);
        xor.execute();
        and_result.push_str(&format!("\n  {:?} -> {:?}", &[v1, v2], and.get_output()));
        or_result.push_str(&format!("\n  {:?} -> {:?}", &[v1, v2], or.get_output()));
        xor_result.push_str(&format!("\n  {:?} -> {:?}", &[v1, v2], xor.get_output()));
    }
    println!("AND component:{}", and_result);
    println!("OR component:{}", or_result);
    println!("XOR component:{}", xor_result);
}<|endoftext|>


<commit_before>#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Erlang {

}<commit_msg>feat: impl constructor for erlang<commit_after>use {Result, StatsError};

/// Implements the [Erlang](https://en.wikipedia.org/wiki/Erlang_distribution) distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Erlang, Continuous};
/// use statrs::statistics::Mean;
/// use statrs::prec;
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Erlang {
    shape: u64,
    rate: f64,
}

impl Erlang {
    /// Constructs a new erlang distribution with a shape (k)
    /// of `shape` and a rate (λ) of `rate`
    ///
    /// # Errors
    ///
    /// Returns an error if `shape` or `rate` are `NaN`.
    /// Also returns an error if `shape == 0` or `rate <= 0.0`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Erlang;
    ///
    /// let mut result = Erlang::new(3, 1.0);
    /// assert!(result.is_ok());
    ///
    /// result = Erlang::new(0, 0.0);
    /// assert!(result.is_err());
    /// ```
    pub fn new(shape: u64, rate: f64) -> Result<Erlang> {
        if rate.is_nan() || shape == 0 || rate <= 0.0 {
            Err(StatsError::BadParams)
        } else {
            Ok(Erlang { shape: shape, rate: rate })
        }
    }

    /// Returns the shape (k) of the erlang distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Erlang;
    ///
    /// let n = Erlang::new(3, 1.0).unwrap();
    /// assert_eq!(n.shape(), 3);
    /// ```
    pub fn shape(&self) -> u64 {
        self.shape
    }

    /// Returns the rate (λ) of the erlang distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Erlang;
    ///
    /// let n = Erlang::new(3, 1.0).unwrap();
    /// assert_eq!(n.rate(), 1.0);
    /// ```
    pub fn rate(&self) -> f64 {
        self.rate
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use std::f64;
    use distribution::{Univariate, Continuous, Erlang};

    fn try_create(shape: u64, rate: f64) -> Erlang {
        let n = Erlang::new(shape, rate);
        assert!(n.is_ok());
        n.unwrap()
    }

    fn create_case(shape: u64, rate: f64) {
        let n = try_create(shape, rate);
        assert_eq!(shape, n.shape());
        assert_eq!(rate, n.rate());
    }

    fn bad_create_case(shape: u64, rate: f64) {
        let n = Erlang::new(shape, rate);
        assert!(n.is_err());
    }

    #[test]
    fn test_create() {
        create_case(1, 0.1);
        create_case(1, 1.0);
        create_case(10, 10.0);
        create_case(10, 1.0);
        create_case(10, f64::INFINITY);
    }

    #[test]
    fn test_bad_create() {
        bad_create_case(0, 1.0);
        bad_create_case(1, 0.0);
        bad_create_case(1, f64::NAN);
        bad_create_case(1, -1.0);
    }
}<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::path::Path;
use toml::Value;
use error::Result;
use failure::err_msg;

/// Metadata for custom builds
///
/// You can customize docs.rs builds by defining `[package.metadata.docs.rs]` table in your
/// crates' `Cargo.toml`.
///
/// An example metadata:
///
/// ```text
/// [package]
/// name = "test"
///
/// [package.metadata.docs.rs]
/// features = [ "feature1", "feature2" ]
/// all-features = true
/// no-default-features = true
/// default-target = "x86_64-unknown-linux-gnu"
/// targets = [ "x86_64-apple-darwin", "x86_64-pc-windows-msvc" ]
/// rustc-args = [ "--example-rustc-arg" ]
/// rustdoc-args = [ "--example-rustdoc-arg" ]
/// ```
///
/// You can define one or more fields in your `Cargo.toml`.
pub struct Metadata {
    /// List of features docs.rs will build.
    ///
    /// By default, docs.rs will only build default features.
    pub features: Option<Vec<String>>,

    /// Set `all-features` to true if you want docs.rs to build all features for your crate
    pub all_features: bool,

    /// Docs.rs will always build default features.
    ///
    /// Set `no-default-fatures` to `false` if you want to build only certain features.
    pub no_default_features: bool,

    /// docs.rs runs on `x86_64-unknown-linux-gnu`, which is the default target for documentation by default.
    ///
    /// You can change the default target by setting this.
    ///
    /// If `default_target` is unset and `targets` is non-empty,
    /// the first element of `targets` will be used as the `default_target`.
    pub default_target: Option<String>,

    /// If you want a crate to build only for specific targets,
    /// set `targets` to the list of targets to build, in addition to `default-target`.
    ///
    /// If you do not set `targets`, all of the tier 1 supported targets will be built.
    /// If you set `targets` to an empty array, only the default target will be built.
    /// If you set `targets` to a non-empty array but do not set `default_target`,
    ///   the first element will be treated as the default.
    pub targets: Option<Vec<String>>,

    /// List of command line arguments for `rustc`.
    pub rustc_args: Option<Vec<String>>,

    /// List of command line arguments for `rustdoc`.
    pub rustdoc_args: Option<Vec<String>>,
}

/// The targets that should be built for a crate.
///
/// The `default_target` is the target to be used as the home page for that crate.
///
/// # See also
/// - [`Metadata::targets`](struct.Metadata.html#method.targets)
pub(super) struct BuildTargets<'a> {
    pub(super) default_target: &'a str,
    pub(super) other_targets: HashSet<&'a str>,
}

impl Metadata {
    pub(crate) fn from_source_dir(source_dir: &Path) -> Result<Metadata> {
        for c in ["Cargo.toml.orig", "Cargo.toml"].iter() {
            let manifest_path = source_dir.clone().join(c);
            if manifest_path.exists() {
                return Ok(Metadata::from_manifest(manifest_path));
            }
        }
        Err(err_msg("Manifest not found"))
    }

    fn from_manifest<P: AsRef<Path>>(path: P) -> Metadata {
        use std::fs::File;
        use std::io::Read;
        let mut f = match File::open(path) {
            Ok(f) => f,
            Err(_) => return Metadata::default(),
        };
        let mut s = String::new();
        if let Err(_) = f.read_to_string(&mut s) {
            return Metadata::default();
        }
        Metadata::from_str(&s)
    }

    // This is similar to Default trait but it's private
    fn default() -> Metadata {
        Metadata {
            features: None,
            all_features: false,
            no_default_features: false,
            default_target: None,
            rustc_args: None,
            rustdoc_args: None,
            targets: None,
        }
    }

    fn from_str(manifest: &str) -> Metadata {
        let mut metadata = Metadata::default();

        let manifest = match manifest.parse::<Value>() {
            Ok(m) => m,
            Err(_) => return metadata,
        };

        if let Some(table) = manifest.get("package").and_then(|p| p.as_table())
            .and_then(|p| p.get("metadata")).and_then(|p| p.as_table())
                .and_then(|p| p.get("docs")).and_then(|p| p.as_table())
                .and_then(|p| p.get("rs")).and_then(|p| p.as_table()) {
                    metadata.features = table.get("features").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                    metadata.no_default_features = table.get("no-default-features")
                        .and_then(|v| v.as_bool()).unwrap_or(metadata.no_default_features);
                    metadata.all_features = table.get("all-features")
                        .and_then(|v| v.as_bool()).unwrap_or(metadata.all_features);
                    metadata.default_target = table.get("default-target")
                        .and_then(|v| v.as_str()).map(|v| v.to_owned());
                    metadata.targets = table.get("targets").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                    metadata.rustc_args = table.get("rustc-args").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                    metadata.rustdoc_args = table.get("rustdoc-args").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                }

        metadata
    }
    // Return (default_target, all other targets that should be built with duplicates removed)
    pub(super) fn targets(&self) -> BuildTargets<'_> {
        use super::rustwide_builder::{HOST_TARGET, TARGETS};

        let default_target = self.default_target.as_deref()
            // Use the first element of `targets` if `default_target` is unset and `targets` is non-empty
            .or_else(|| self.targets.as_ref().and_then(|targets| targets.iter().next().map(String::as_str)))
            .unwrap_or(HOST_TARGET);

        // Let people opt-in to only having specific targets
        let mut targets: HashSet<_> = self.targets.as_ref()
            .map(|targets| targets.iter().map(String::as_str).collect())
            .unwrap_or_else(|| TARGETS.iter().copied().collect());

        targets.remove(&default_target);
        BuildTargets { default_target, other_targets: targets }
    }
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use super::Metadata;

    #[test]
    fn test_cratesfyi_metadata() {
        let _ = env_logger::try_init();
        let manifest = r#"
            [package]
            name = "test"

            [package.metadata.docs.rs]
            features = [ "feature1", "feature2" ]
            all-features = true
            no-default-features = true
            default-target = "x86_64-unknown-linux-gnu"
            targets = [ "x86_64-apple-darwin", "x86_64-pc-windows-msvc" ]
            rustc-args = [ "--example-rustc-arg" ]
            rustdoc-args = [ "--example-rustdoc-arg" ]
        "#;

        let metadata = Metadata::from_str(manifest);

        assert!(metadata.features.is_some());
        assert!(metadata.all_features == true);
        assert!(metadata.no_default_features == true);
        assert!(metadata.default_target.is_some());
        assert!(metadata.rustdoc_args.is_some());

        let features = metadata.features.unwrap();
        assert_eq!(features.len(), 2);
        assert_eq!(features[0], "feature1".to_owned());
        assert_eq!(features[1], "feature2".to_owned());

        assert_eq!(metadata.default_target.unwrap(), "x86_64-unknown-linux-gnu".to_owned());

        let targets = metadata.targets.expect("should have explicit target");
        assert_eq!(targets.len(), 2);
        assert_eq!(targets[0], "x86_64-apple-darwin");
        assert_eq!(targets[1], "x86_64-pc-windows-msvc");

        let rustc_args = metadata.rustc_args.unwrap();
        assert_eq!(rustc_args.len(), 1);
        assert_eq!(rustc_args[0], "--example-rustc-arg".to_owned());

        let rustdoc_args = metadata.rustdoc_args.unwrap();
        assert_eq!(rustdoc_args.len(), 1);
        assert_eq!(rustdoc_args[0], "--example-rustdoc-arg".to_owned());
    }

    #[test]
    fn test_no_targets() {
        // metadata section but no targets
        let manifest = r#"
            [package]
            name = "test"

            [package.metadata.docs.rs]
            features = [ "feature1", "feature2" ]
        "#;
        let metadata = Metadata::from_str(manifest);
        assert!(metadata.targets.is_none());

        // no package.metadata.docs.rs section
        let metadata = Metadata::from_str(r#"
            [package]
            name = "test"
        "#);
        assert!(metadata.targets.is_none());

        // targets explicitly set to empty array
        let metadata = Metadata::from_str(r#"
            [package.metadata.docs.rs]
            targets = []
        "#);
        assert!(metadata.targets.unwrap().is_empty());
    }
    #[test]
    fn test_select_targets() {
        use crate::docbuilder::rustwide_builder::{HOST_TARGET, TARGETS};
        use super::BuildTargets;

        let mut metadata = Metadata::default();
        // unchanged default_target, targets not specified
        let BuildTargets { default_target: default, other_targets: tier_one } = metadata.targets();
        assert_eq!(default, HOST_TARGET);
        // should be equal to TARGETS \ {HOST_TARGET}
        for actual in &tier_one {
            assert!(TARGETS.contains(actual));
        }
        for expected in TARGETS {
            if *expected == HOST_TARGET {
                assert!(!tier_one.contains(&HOST_TARGET));
            } else {
                assert!(tier_one.contains(expected));
            }
        }

        // unchanged default_target, targets specified to be empty
        metadata.targets = Some(Vec::new());
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, HOST_TARGET);
        assert!(others.is_empty());

        // unchanged default_target, targets non-empty
        metadata.targets = Some(vec!["i686-pc-windows-msvc".into(), "i686-apple-darwin".into()]);
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, "i686-pc-windows-msvc");
        assert_eq!(others.len(), 1);
        assert!(others.contains(&"i686-apple-darwin"));

        // make sure that default_target is not built twice
        metadata.targets = Some(vec![HOST_TARGET.into()]);
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, HOST_TARGET);
        assert!(others.is_empty());

        // make sure that duplicates are removed
        metadata.targets = Some(vec!["i686-pc-windows-msvc".into(), "i686-pc-windows-msvc".into()]);
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, "i686-pc-windows-msvc");
        assert!(others.is_empty());

        // make sure that `default_target` always takes priority over `targets`
        metadata.default_target = Some("i686-apple-darwin".into());
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, "i686-apple-darwin");
        assert_eq!(others.len(), 1);
        assert!(others.contains(&"i686-pc-windows-msvc"));

        // make sure that `default_target` takes priority over `HOST_TARGET`
        metadata.targets = Some(vec![]);
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, "i686-apple-darwin");
        assert!(others.is_empty());

        // and if `targets` is unset, it should still be set to `TARGETS`
        metadata.targets = None;
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, "i686-apple-darwin");
        let tier_one_targets_no_default = TARGETS.iter().filter(|&&t| t != "i686-apple-darwin").copied().collect();
        assert_eq!(others, tier_one_targets_no_default);
    }
}
<commit_msg>Remove out-of-date comment<commit_after>use std::collections::HashSet;
use std::path::Path;
use toml::Value;
use error::Result;
use failure::err_msg;

/// Metadata for custom builds
///
/// You can customize docs.rs builds by defining `[package.metadata.docs.rs]` table in your
/// crates' `Cargo.toml`.
///
/// An example metadata:
///
/// ```text
/// [package]
/// name = "test"
///
/// [package.metadata.docs.rs]
/// features = [ "feature1", "feature2" ]
/// all-features = true
/// no-default-features = true
/// default-target = "x86_64-unknown-linux-gnu"
/// targets = [ "x86_64-apple-darwin", "x86_64-pc-windows-msvc" ]
/// rustc-args = [ "--example-rustc-arg" ]
/// rustdoc-args = [ "--example-rustdoc-arg" ]
/// ```
///
/// You can define one or more fields in your `Cargo.toml`.
pub struct Metadata {
    /// List of features docs.rs will build.
    ///
    /// By default, docs.rs will only build default features.
    pub features: Option<Vec<String>>,

    /// Set `all-features` to true if you want docs.rs to build all features for your crate
    pub all_features: bool,

    /// Docs.rs will always build default features.
    ///
    /// Set `no-default-fatures` to `false` if you want to build only certain features.
    pub no_default_features: bool,

    /// docs.rs runs on `x86_64-unknown-linux-gnu`, which is the default target for documentation by default.
    ///
    /// You can change the default target by setting this.
    ///
    /// If `default_target` is unset and `targets` is non-empty,
    /// the first element of `targets` will be used as the `default_target`.
    pub default_target: Option<String>,

    /// If you want a crate to build only for specific targets,
    /// set `targets` to the list of targets to build, in addition to `default-target`.
    ///
    /// If you do not set `targets`, all of the tier 1 supported targets will be built.
    /// If you set `targets` to an empty array, only the default target will be built.
    /// If you set `targets` to a non-empty array but do not set `default_target`,
    ///   the first element will be treated as the default.
    pub targets: Option<Vec<String>>,

    /// List of command line arguments for `rustc`.
    pub rustc_args: Option<Vec<String>>,

    /// List of command line arguments for `rustdoc`.
    pub rustdoc_args: Option<Vec<String>>,
}

/// The targets that should be built for a crate.
///
/// The `default_target` is the target to be used as the home page for that crate.
///
/// # See also
/// - [`Metadata::targets`](struct.Metadata.html#method.targets)
pub(super) struct BuildTargets<'a> {
    pub(super) default_target: &'a str,
    pub(super) other_targets: HashSet<&'a str>,
}

impl Metadata {
    pub(crate) fn from_source_dir(source_dir: &Path) -> Result<Metadata> {
        for c in ["Cargo.toml.orig", "Cargo.toml"].iter() {
            let manifest_path = source_dir.clone().join(c);
            if manifest_path.exists() {
                return Ok(Metadata::from_manifest(manifest_path));
            }
        }
        Err(err_msg("Manifest not found"))
    }

    fn from_manifest<P: AsRef<Path>>(path: P) -> Metadata {
        use std::fs::File;
        use std::io::Read;
        let mut f = match File::open(path) {
            Ok(f) => f,
            Err(_) => return Metadata::default(),
        };
        let mut s = String::new();
        if let Err(_) = f.read_to_string(&mut s) {
            return Metadata::default();
        }
        Metadata::from_str(&s)
    }

    // This is similar to Default trait but it's private
    fn default() -> Metadata {
        Metadata {
            features: None,
            all_features: false,
            no_default_features: false,
            default_target: None,
            rustc_args: None,
            rustdoc_args: None,
            targets: None,
        }
    }

    fn from_str(manifest: &str) -> Metadata {
        let mut metadata = Metadata::default();

        let manifest = match manifest.parse::<Value>() {
            Ok(m) => m,
            Err(_) => return metadata,
        };

        if let Some(table) = manifest.get("package").and_then(|p| p.as_table())
            .and_then(|p| p.get("metadata")).and_then(|p| p.as_table())
                .and_then(|p| p.get("docs")).and_then(|p| p.as_table())
                .and_then(|p| p.get("rs")).and_then(|p| p.as_table()) {
                    metadata.features = table.get("features").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                    metadata.no_default_features = table.get("no-default-features")
                        .and_then(|v| v.as_bool()).unwrap_or(metadata.no_default_features);
                    metadata.all_features = table.get("all-features")
                        .and_then(|v| v.as_bool()).unwrap_or(metadata.all_features);
                    metadata.default_target = table.get("default-target")
                        .and_then(|v| v.as_str()).map(|v| v.to_owned());
                    metadata.targets = table.get("targets").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                    metadata.rustc_args = table.get("rustc-args").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                    metadata.rustdoc_args = table.get("rustdoc-args").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                }

        metadata
    }
    pub(super) fn targets(&self) -> BuildTargets<'_> {
        use super::rustwide_builder::{HOST_TARGET, TARGETS};

        let default_target = self.default_target.as_deref()
            // Use the first element of `targets` if `default_target` is unset and `targets` is non-empty
            .or_else(|| self.targets.as_ref().and_then(|targets| targets.iter().next().map(String::as_str)))
            .unwrap_or(HOST_TARGET);

        // Let people opt-in to only having specific targets
        let mut targets: HashSet<_> = self.targets.as_ref()
            .map(|targets| targets.iter().map(String::as_str).collect())
            .unwrap_or_else(|| TARGETS.iter().copied().collect());

        targets.remove(&default_target);
        BuildTargets { default_target, other_targets: targets }
    }
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use super::Metadata;

    #[test]
    fn test_cratesfyi_metadata() {
        let _ = env_logger::try_init();
        let manifest = r#"
            [package]
            name = "test"

            [package.metadata.docs.rs]
            features = [ "feature1", "feature2" ]
            all-features = true
            no-default-features = true
            default-target = "x86_64-unknown-linux-gnu"
            targets = [ "x86_64-apple-darwin", "x86_64-pc-windows-msvc" ]
            rustc-args = [ "--example-rustc-arg" ]
            rustdoc-args = [ "--example-rustdoc-arg" ]
        "#;

        let metadata = Metadata::from_str(manifest);

        assert!(metadata.features.is_some());
        assert!(metadata.all_features == true);
        assert!(metadata.no_default_features == true);
        assert!(metadata.default_target.is_some());
        assert!(metadata.rustdoc_args.is_some());

        let features = metadata.features.unwrap();
        assert_eq!(features.len(), 2);
        assert_eq!(features[0], "feature1".to_owned());
        assert_eq!(features[1], "feature2".to_owned());

        assert_eq!(metadata.default_target.unwrap(), "x86_64-unknown-linux-gnu".to_owned());

        let targets = metadata.targets.expect("should have explicit target");
        assert_eq!(targets.len(), 2);
        assert_eq!(targets[0], "x86_64-apple-darwin");
        assert_eq!(targets[1], "x86_64-pc-windows-msvc");

        let rustc_args = metadata.rustc_args.unwrap();
        assert_eq!(rustc_args.len(), 1);
        assert_eq!(rustc_args[0], "--example-rustc-arg".to_owned());

        let rustdoc_args = metadata.rustdoc_args.unwrap();
        assert_eq!(rustdoc_args.len(), 1);
        assert_eq!(rustdoc_args[0], "--example-rustdoc-arg".to_owned());
    }

    #[test]
    fn test_no_targets() {
        // metadata section but no targets
        let manifest = r#"
            [package]
            name = "test"

            [package.metadata.docs.rs]
            features = [ "feature1", "feature2" ]
        "#;
        let metadata = Metadata::from_str(manifest);
        assert!(metadata.targets.is_none());

        // no package.metadata.docs.rs section
        let metadata = Metadata::from_str(r#"
            [package]
            name = "test"
        "#);
        assert!(metadata.targets.is_none());

        // targets explicitly set to empty array
        let metadata = Metadata::from_str(r#"
            [package.metadata.docs.rs]
            targets = []
        "#);
        assert!(metadata.targets.unwrap().is_empty());
    }
    #[test]
    fn test_select_targets() {
        use crate::docbuilder::rustwide_builder::{HOST_TARGET, TARGETS};
        use super::BuildTargets;

        let mut metadata = Metadata::default();
        // unchanged default_target, targets not specified
        let BuildTargets { default_target: default, other_targets: tier_one } = metadata.targets();
        assert_eq!(default, HOST_TARGET);
        // should be equal to TARGETS \ {HOST_TARGET}
        for actual in &tier_one {
            assert!(TARGETS.contains(actual));
        }
        for expected in TARGETS {
            if *expected == HOST_TARGET {
                assert!(!tier_one.contains(&HOST_TARGET));
            } else {
                assert!(tier_one.contains(expected));
            }
        }

        // unchanged default_target, targets specified to be empty
        metadata.targets = Some(Vec::new());
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, HOST_TARGET);
        assert!(others.is_empty());

        // unchanged default_target, targets non-empty
        metadata.targets = Some(vec!["i686-pc-windows-msvc".into(), "i686-apple-darwin".into()]);
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, "i686-pc-windows-msvc");
        assert_eq!(others.len(), 1);
        assert!(others.contains(&"i686-apple-darwin"));

        // make sure that default_target is not built twice
        metadata.targets = Some(vec![HOST_TARGET.into()]);
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, HOST_TARGET);
        assert!(others.is_empty());

        // make sure that duplicates are removed
        metadata.targets = Some(vec!["i686-pc-windows-msvc".into(), "i686-pc-windows-msvc".into()]);
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, "i686-pc-windows-msvc");
        assert!(others.is_empty());

        // make sure that `default_target` always takes priority over `targets`
        metadata.default_target = Some("i686-apple-darwin".into());
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, "i686-apple-darwin");
        assert_eq!(others.len(), 1);
        assert!(others.contains(&"i686-pc-windows-msvc"));

        // make sure that `default_target` takes priority over `HOST_TARGET`
        metadata.targets = Some(vec![]);
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, "i686-apple-darwin");
        assert!(others.is_empty());

        // and if `targets` is unset, it should still be set to `TARGETS`
        metadata.targets = None;
        let BuildTargets { default_target: default, other_targets: others } = metadata.targets();
        assert_eq!(default, "i686-apple-darwin");
        let tier_one_targets_no_default = TARGETS.iter().filter(|&&t| t != "i686-apple-darwin").copied().collect();
        assert_eq!(others, tier_one_targets_no_default);
    }
}
<|endoftext|>


<commit_before>//! An information element is a portion of a SBD message.
//!
//! Information elements come after the SBD header. They come in many types, including more
//! header-type information and the actual data payload.

use std::io::{Cursor, Read};

use byteorder::{ReadBytesExt, BigEndian};

use {Error, Result};

/// Indicates the success or failure of the SBD session.
enum_from_primitive! {
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SessionStatus {
    Ok = 0,
    OkMobileTerminatedTooLarge = 1,
    OkLocationUnacceptableQuality = 2,
    Timeout = 10,
    MobileOriginatedTooLarge = 12,
    RFLinkLoss = 13,
    IMEIProtocolAnomaly = 14,
    Prohibited = 15,
    Unknown,
}
}

/// An information element, or IE.
///
/// These are the building blocks of a SBD message. There are several types, generally divided into
/// MO and MT IE's. This general structure just holds the basic IE data, when then can be converted
/// into a specific type of IE.
#[derive(Debug, Default)]
pub struct InformationElement {
    id: u8,
    length: u16,
    contents: Vec<u8>,
}

impl InformationElement {

    /// Reads an information element from something that implements `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::{Read, Seek, SeekFrom};
    /// use std::fs::File;
    /// use sbd::information_element::InformationElement;
    /// let mut file = File::open("data/0-mo.sbd").unwrap();
    /// file.seek(SeekFrom::Start(3)).unwrap();
    /// let readable = file.take(31);
    /// InformationElement::read_from(readable).unwrap();
    /// ```
    pub fn read_from<R: Read>(mut readable: R) -> Result<InformationElement> {
        let mut information_element: InformationElement = Default::default();
        information_element.id = try!(readable.read_u8());
        information_element.length = try!(readable.read_u16::<BigEndian>());
        let bytes_read = try!(readable.take(information_element.length as u64)
                              .read_to_end(&mut information_element.contents));
        assert!(!(bytes_read > information_element.length as usize));
        if bytes_read < information_element.length as usize {
            return Err(Error::Undersized(bytes_read + 3));
        }
        Ok(information_element)
    }

    /// Returns the length of the information element.
    ///
    /// This is not the same as the internal length, but is rather the length of the contents plus
    /// the length of the IE header.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::io::{Read, Seek, SeekFrom};
    /// # use std::fs::File;
    /// # use sbd::information_element::InformationElement;
    /// # let mut file = File::open("data/0-mo.sbd").unwrap();
    /// # file.seek(SeekFrom::Start(3)).unwrap();
    /// # let readable = file.take(31);
    /// let information_element = InformationElement::read_from(readable).unwrap();
    /// assert_eq!(31, information_element.len());
    /// ```
    pub fn len(&self) -> u16 {
        self.length + 3
    }

    /// Returns the id of the information element.
    pub fn id(&self) -> u8 {
        self.id
    }

    /// Returns a object that can `Read` over the contents of this information element.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::io::{Read, Seek, SeekFrom};
    /// # use std::fs::File;
    /// # use sbd::information_element::InformationElement;
    /// # let mut file = File::open("data/0-mo.sbd").unwrap();
    /// # file.seek(SeekFrom::Start(3)).unwrap();
    /// # let readable = file.take(31);
    /// let information_element = InformationElement::read_from(readable).unwrap();
    /// let mut readable = information_element.as_contents_reader();
    /// let mut buffer: Vec<u8> = Vec::new();
    /// readable.read_to_end(&mut buffer);
    /// ```
    pub fn as_contents_reader<'a>(&self) -> Cursor<&[u8]> {
        Cursor::new(&self.contents[..])
    }
}

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

    use std::io::{Read, Seek, SeekFrom};
    use std::fs::File;

    #[test]
    fn read_from() {
        let mut file = File::open("data/0-mo.sbd").unwrap();
        file.seek(SeekFrom::Start(3)).unwrap();
        let readable = file.take(31);
        InformationElement::read_from(readable).unwrap();
    }

    #[test]
    fn len() {
        let mut file = File::open("data/0-mo.sbd").unwrap();
        file.seek(SeekFrom::Start(3)).unwrap();
        let readable = file.take(31);
        let ie = InformationElement::read_from(readable).unwrap();
        assert_eq!(31, ie.len());
    }

    #[test]
    fn undersized() {
        let mut file = File::open("data/0-mo.sbd").unwrap();
        file.seek(SeekFrom::Start(3)).unwrap();
        let readable = file.take(30);
        assert!(InformationElement::read_from(readable).is_err());
    }
}
<commit_msg>Change magic number to constant<commit_after>//! An information element is a portion of a SBD message.
//!
//! Information elements come after the SBD header. They come in many types, including more
//! header-type information and the actual data payload.

use std::io::{Cursor, Read};

use byteorder::{ReadBytesExt, BigEndian};

use {Error, Result};

const INFORMATION_ELEMENT_HEADER_LENGTH: u16 = 3;

/// Indicates the success or failure of the SBD session.
enum_from_primitive! {
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SessionStatus {
    Ok = 0,
    OkMobileTerminatedTooLarge = 1,
    OkLocationUnacceptableQuality = 2,
    Timeout = 10,
    MobileOriginatedTooLarge = 12,
    RFLinkLoss = 13,
    IMEIProtocolAnomaly = 14,
    Prohibited = 15,
    Unknown,
}
}

/// An information element, or IE.
///
/// These are the building blocks of a SBD message. There are several types, generally divided into
/// MO and MT IE's. This general structure just holds the basic IE data, when then can be converted
/// into a specific type of IE.
#[derive(Debug, Default)]
pub struct InformationElement {
    id: u8,
    length: u16,
    contents: Vec<u8>,
}

impl InformationElement {

    /// Reads an information element from something that implements `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::{Read, Seek, SeekFrom};
    /// use std::fs::File;
    /// use sbd::information_element::InformationElement;
    /// let mut file = File::open("data/0-mo.sbd").unwrap();
    /// file.seek(SeekFrom::Start(3)).unwrap();
    /// let readable = file.take(31);
    /// InformationElement::read_from(readable).unwrap();
    /// ```
    pub fn read_from<R: Read>(mut readable: R) -> Result<InformationElement> {
        let mut information_element: InformationElement = Default::default();
        information_element.id = try!(readable.read_u8());
        information_element.length = try!(readable.read_u16::<BigEndian>());
        let bytes_read = try!(readable.take(information_element.length as u64)
                              .read_to_end(&mut information_element.contents));
        assert!(!(bytes_read > information_element.length as usize));
        if bytes_read < information_element.length as usize {
            return Err(Error::Undersized(bytes_read + 3));
        }
        Ok(information_element)
    }

    /// Returns the length of the information element.
    ///
    /// This is not the same as the internal length, but is rather the length of the contents plus
    /// the length of the IE header.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::io::{Read, Seek, SeekFrom};
    /// # use std::fs::File;
    /// # use sbd::information_element::InformationElement;
    /// # let mut file = File::open("data/0-mo.sbd").unwrap();
    /// # file.seek(SeekFrom::Start(3)).unwrap();
    /// # let readable = file.take(31);
    /// let information_element = InformationElement::read_from(readable).unwrap();
    /// assert_eq!(31, information_element.len());
    /// ```
    pub fn len(&self) -> u16 {
        self.length + INFORMATION_ELEMENT_HEADER_LENGTH
    }

    /// Returns the id of the information element.
    pub fn id(&self) -> u8 {
        self.id
    }

    /// Returns a object that can `Read` over the contents of this information element.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::io::{Read, Seek, SeekFrom};
    /// # use std::fs::File;
    /// # use sbd::information_element::InformationElement;
    /// # let mut file = File::open("data/0-mo.sbd").unwrap();
    /// # file.seek(SeekFrom::Start(3)).unwrap();
    /// # let readable = file.take(31);
    /// let information_element = InformationElement::read_from(readable).unwrap();
    /// let mut readable = information_element.as_contents_reader();
    /// let mut buffer: Vec<u8> = Vec::new();
    /// readable.read_to_end(&mut buffer);
    /// ```
    pub fn as_contents_reader<'a>(&self) -> Cursor<&[u8]> {
        Cursor::new(&self.contents[..])
    }
}

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

    use std::io::{Read, Seek, SeekFrom};
    use std::fs::File;

    #[test]
    fn read_from() {
        let mut file = File::open("data/0-mo.sbd").unwrap();
        file.seek(SeekFrom::Start(3)).unwrap();
        let readable = file.take(31);
        InformationElement::read_from(readable).unwrap();
    }

    #[test]
    fn len() {
        let mut file = File::open("data/0-mo.sbd").unwrap();
        file.seek(SeekFrom::Start(3)).unwrap();
        let readable = file.take(31);
        let ie = InformationElement::read_from(readable).unwrap();
        assert_eq!(31, ie.len());
    }

    #[test]
    fn undersized() {
        let mut file = File::open("data/0-mo.sbd").unwrap();
        file.seek(SeekFrom::Start(3)).unwrap();
        let readable = file.take(30);
        assert!(InformationElement::read_from(readable).is_err());
    }
}
<|endoftext|>