<commit_before>use {Run, Segment, TimeSpan, Timer, TimingMethod};
use run::Editor;

fn run() -> Run {
    let mut run = Run::new();

    run.push_segment(Segment::new("A"));
    run.push_segment(Segment::new("B"));
    run.push_segment(Segment::new("C"));

    run
}

fn timer() -> Timer {
    let mut timer = Timer::new(run()).unwrap();

    timer.start();
    timer.initialize_game_time();
    timer.pause_game_time();

    timer
}

#[test]
fn monotically_increasing_split_times_after_resetting() {
    let mut timer = timer();

    let first = TimeSpan::from_seconds(5.0);
    timer.set_game_time(first);
    timer.split();

    let second = TimeSpan::from_seconds(15.0);
    timer.set_game_time(second);
    timer.split();

    let third = TimeSpan::from_seconds(10.0);
    timer.set_game_time(third);
    timer.split();

    let run = timer.into_run(true);

    assert_eq!(
        run.segment(0).personal_best_split_time().game_time,
        Some(first)
    );

    assert_eq!(
        run.segment(1).personal_best_split_time().game_time,
        Some(second)
    );

    assert_eq!(
        run.segment(2).personal_best_split_time().game_time,
        Some(second)
    );
}

#[test]
fn deleting_best_segment_time_clears_segment_history() {
    let mut timer = timer();

    let first = TimeSpan::from_seconds(5.0);
    timer.set_game_time(first);
    timer.split();

    let second = TimeSpan::from_seconds(10.0);
    timer.set_game_time(second);
    timer.split();

    let third = TimeSpan::from_seconds(15.0);
    timer.set_game_time(third);
    timer.split();

    let run = timer.into_run(true);
    let run2 = run.clone();

    // =============================================

    let mut editor = Editor::new(run).unwrap();

    editor.select_timing_method(TimingMethod::GameTime);
    editor.select_only(1);
    editor.active_segment().set_split_time(None);

    assert_eq!(
        editor.run().segment(1).best_segment_time().game_time,
        Some(second - first)
    );

    editor.active_segment().set_best_segment_time(None);

    assert_eq!(
        editor.run().segment(1).segment_history().iter().next(),
        None
    );
    assert_eq!(editor.run().segment(1).best_segment_time().game_time, None);

    // =============================================

    editor = Editor::new(run2).unwrap();

    editor.select_timing_method(TimingMethod::GameTime);
    editor.select_only(1);
    editor.active_segment().set_best_segment_time(None);

    assert_eq!(
        editor.run().segment(1).segment_history().iter().next(),
        None
    );
    assert_eq!(
        editor.run().segment(1).best_segment_time().game_time,
        Some(second - first)
    );
}

#[test]
fn modifying_best_segment_time_fixes_segment_history() {
    let mut timer = timer();

    let first = TimeSpan::from_seconds(5.0);
    timer.set_game_time(first);
    timer.split();

    let second = TimeSpan::from_seconds(10.0);
    timer.set_game_time(second);
    timer.split();

    let third = TimeSpan::from_seconds(15.0);
    timer.set_game_time(third);
    timer.split();

    let run = timer.into_run(true);
    let run2 = run.clone();

    // =============================================

    let mut editor = Editor::new(run).unwrap();

    editor.select_timing_method(TimingMethod::GameTime);
    editor.select_only(1);
    editor.active_segment().set_split_time(None);

    assert_eq!(
        editor.run().segment(1).best_segment_time().game_time,
        Some(second - first)
    );

    let new_best = Some(TimeSpan::from_seconds(7.0));

    editor.active_segment().set_best_segment_time(new_best);

    assert_eq!(
        editor
            .run()
            .segment(1)
            .segment_history()
            .iter()
            .next()
            .and_then(|&(_, t)| t.game_time),
        new_best
    );
    assert_eq!(
        editor.run().segment(1).best_segment_time().game_time,
        new_best
    );

    // =============================================

    editor = Editor::new(run2).unwrap();

    editor.select_timing_method(TimingMethod::GameTime);
    editor.select_only(1);
    editor.active_segment().set_best_segment_time(new_best);

    assert_eq!(
        editor
            .run()
            .segment(1)
            .segment_history()
            .iter()
            .next()
            .and_then(|&(_, t)| t.game_time),
        Some(second - first)
    );
    assert_eq!(
        editor.run().segment(1).best_segment_time().game_time,
        Some(second - first)
    );
}

#[test]
fn import_pb_into_segment_history() {
    let mut editor = Editor::new(run()).unwrap();
    editor.select_timing_method(TimingMethod::GameTime);

    editor.select_only(0);
    let fake_first = Some(TimeSpan::from_seconds(5.0));
    editor.active_segment().set_split_time(fake_first);

    editor.select_only(1);
    let fake_second = Some(TimeSpan::from_seconds(10.0));
    editor.active_segment().set_split_time(fake_second);

    editor.select_only(2);
    let fake_third = Some(TimeSpan::from_seconds(15.0));
    editor.active_segment().set_split_time(fake_third);

    let run = editor.close();
    let mut timer = Timer::new(run).unwrap();

    timer.start();
    timer.initialize_game_time();
    timer.pause_game_time();

    let real_first = TimeSpan::from_seconds(4.0);
    timer.set_game_time(real_first);
    timer.split();

    let real_second = TimeSpan::from_seconds(9.0);
    timer.set_game_time(real_second);
    timer.split();

    let real_third = TimeSpan::from_seconds(13.0);
    timer.set_game_time(real_third);
    timer.split();

    timer.reset(true);

    let run = timer.run();

    assert_eq!(
        run.segment(0)
            .segment_history()
            .get(-1)
            .and_then(|t| t.game_time),
        fake_first
    );
    assert_eq!(
        run.segment(0)
            .segment_history()
            .get(1)
            .and_then(|t| t.game_time),
        Some(real_first)
    );

    assert_eq!(run.segment(1).segment_history().get(-1), None);
    assert_eq!(
        run.segment(1)
            .segment_history()
            .get(1)
            .and_then(|t| t.game_time),
        Some(real_second - real_first)
    );

    assert_eq!(
        run.segment(2)
            .segment_history()
            .get(-1)
            .and_then(|t| t.game_time),
        catch! { fake_third? - fake_second? }
    );
    assert_eq!(
        run.segment(2)
            .segment_history()
            .get(1)
            .and_then(|t| t.game_time),
        Some(real_third - real_second)
    );
}

#[test]
fn import_pb_into_segment_history_and_remove_null_values() {
    let mut editor = Editor::new(run()).unwrap();
    editor.select_timing_method(TimingMethod::GameTime);

    editor.select_only(0);
    let fake_first = Some(TimeSpan::from_seconds(5.0));
    editor.active_segment().set_split_time(fake_first);

    editor.select_only(2);
    let fake_third = Some(TimeSpan::from_seconds(15.0));
    editor.active_segment().set_split_time(fake_third);

    let run = editor.close();
    let mut timer = Timer::new(run).unwrap();

    timer.start();
    timer.initialize_game_time();
    timer.pause_game_time();

    let real_first = TimeSpan::from_seconds(4.0);
    timer.set_game_time(real_first);
    timer.split();

    timer.skip_split();

    let real_third = TimeSpan::from_seconds(14.0);
    timer.set_game_time(real_third);
    timer.split();

    timer.reset(true);

    let run = timer.run();

    assert_eq!(
        run.segment(0)
            .segment_history()
            .get(-1)
            .and_then(|t| t.game_time),
        fake_first
    );
    assert_eq!(
        run.segment(0)
            .segment_history()
            .get(1)
            .and_then(|t| t.game_time),
        Some(real_first)
    );

    assert_eq!(run.segment(1).segment_history().get(-1), None);
    assert_eq!(
        run.segment(1).segment_history().get(1).map(|t| t.game_time),
        Some(None)
    );

    assert_eq!(run.segment(2).segment_history().get(-1), None);
    assert_eq!(
        run.segment(2)
            .segment_history()
            .get(1)
            .and_then(|t| t.game_time),
        Some(real_third - real_first)
    );
}

#[test]
fn import_best_segment_with_game_time_usage() {
    let mut timer = timer();

    let first = TimeSpan::from_seconds(5.0);
    timer.set_game_time(first);
    timer.split();

    let run = timer.into_run(true);
    let mut editor = Editor::new(run).unwrap();

    editor.select_timing_method(TimingMethod::GameTime);

    editor.select_only(0);
    let best = Some(TimeSpan::from_seconds(4.0));
    editor.active_segment().set_best_segment_time(best);

    editor.insert_segment_above();

    let history = editor.run().segment(0).segment_history();
    assert_eq!(history.get(0).map(|t| t.game_time), Some(None));
    assert_eq!(history.get(1).map(|t| t.game_time), Some(None));

    let history = editor.run().segment(1).segment_history();
    assert_eq!(history.get(0).and_then(|t| t.game_time), best);
    assert_eq!(history.get(1).and_then(|t| t.game_time), Some(first));
}

#[test]
fn clears_run_id_when_pbing() {
    let mut timer = timer();

    // Get a PB

    timer.set_current_timing_method(TimingMethod::GameTime);

    let first = TimeSpan::from_seconds(5.0);
    timer.set_game_time(first);
    timer.split();

    let second = TimeSpan::from_seconds(10.0);
    timer.set_game_time(second);
    timer.split();

    let third = TimeSpan::from_seconds(15.0);
    timer.set_game_time(third);
    timer.split();

    let mut run = timer.into_run(true);

    // Set the run id

    assert_eq!(run.metadata().run_id(), "");
    run.metadata_mut().set_run_id("34567");
    assert_eq!(run.metadata().run_id(), "34567");

    // Do a new run, but this time don't pb. Run ID should be the same.

    let mut timer = Timer::new(run).unwrap();
    timer.set_current_timing_method(TimingMethod::GameTime);

    timer.start();
    timer.initialize_game_time();
    timer.pause_game_time();

    let first = TimeSpan::from_seconds(6.0);
    timer.set_game_time(first);
    timer.split();

    let second = TimeSpan::from_seconds(11.0);
    timer.set_game_time(second);
    timer.split();

    let third = TimeSpan::from_seconds(16.0);
    timer.set_game_time(third);
    timer.split();

    timer.reset(true);

    assert_eq!(timer.run().metadata().run_id(), "34567");

    // Do a new run and PB. Run ID should be cleared.

    timer.start();
    timer.initialize_game_time();
    timer.pause_game_time();

    let first = TimeSpan::from_seconds(4.0);
    timer.set_game_time(first);
    timer.split();

    let second = TimeSpan::from_seconds(9.0);
    timer.set_game_time(second);
    timer.split();

    let third = TimeSpan::from_seconds(14.0);
    timer.set_game_time(third);
    timer.split();

    timer.reset(true);

    assert_eq!(timer.run().metadata().run_id(), "");
}
<commit_msg>Add comments to describe asserts in tests<commit_after>use {Run, Segment, TimeSpan, Timer, TimingMethod};
use run::Editor;

fn run() -> Run {
    let mut run = Run::new();

    run.push_segment(Segment::new("A"));
    run.push_segment(Segment::new("B"));
    run.push_segment(Segment::new("C"));

    run
}

fn timer() -> Timer {
    let mut timer = Timer::new(run()).unwrap();

    timer.start();
    timer.initialize_game_time();
    timer.pause_game_time();

    timer
}

#[test]
fn monotically_increasing_split_times_after_resetting() {
    let mut timer = timer();

    let first = TimeSpan::from_seconds(5.0);
    timer.set_game_time(first);
    timer.split();

    let second = TimeSpan::from_seconds(15.0);
    timer.set_game_time(second);
    timer.split();

    let third = TimeSpan::from_seconds(10.0);
    timer.set_game_time(third);
    timer.split();

    let run = timer.into_run(true);

    // The first segment's time should be unchanged.
    assert_eq!(
        run.segment(0).personal_best_split_time().game_time,
        Some(first)
    );

    // 15.0 is larger than 5.0, so the second segment's time should be
    // unchanged.
    assert_eq!(
        run.segment(1).personal_best_split_time().game_time,
        Some(second)
    );

    // 10.0 is less than 15.0, and since we want split times to be monotonically
    // increasing, the third segment's time should be adjusted to 15.0.
    assert_eq!(
        run.segment(2).personal_best_split_time().game_time,
        Some(second)
    );
}

#[test]
fn deleting_best_segment_time_clears_segment_history() {
    let mut timer = timer();

    let first = TimeSpan::from_seconds(5.0);
    timer.set_game_time(first);
    timer.split();

    let second = TimeSpan::from_seconds(10.0);
    timer.set_game_time(second);
    timer.split();

    let third = TimeSpan::from_seconds(15.0);
    timer.set_game_time(third);
    timer.split();

    let run = timer.into_run(true);
    let run2 = run.clone();

    // =============================================

    let mut editor = Editor::new(run).unwrap();

    editor.select_timing_method(TimingMethod::GameTime);
    editor.select_only(1);
    editor.active_segment().set_split_time(None);

    // Clearing the second segment's split time should not affect the second
    // segment's best segment time.
    assert_eq!(
        editor.run().segment(1).best_segment_time().game_time,
        Some(second - first)
    );

    editor.active_segment().set_best_segment_time(None);

    // Since the second segment's split time is already cleared, clearing its
    // best segment time should clear the segment history and leave the best
    // segment time as blank.
    assert_eq!(
        editor.run().segment(1).segment_history().iter().next(),
        None
    );
    assert_eq!(editor.run().segment(1).best_segment_time().game_time, None);

    // =============================================

    editor = Editor::new(run2).unwrap();

    editor.select_timing_method(TimingMethod::GameTime);
    editor.select_only(1);
    editor.active_segment().set_best_segment_time(None);

    // Clearing the second segment's best segment time without clearing its
    // split time should still clear its segment history.
    assert_eq!(
        editor.run().segment(1).segment_history().iter().next(),
        None
    );
    // Since the second segment's split time was not cleared, the best segment
    // time should be fixed based on the personal best split times.
    assert_eq!(
        editor.run().segment(1).best_segment_time().game_time,
        Some(second - first)
    );
}

#[test]
fn modifying_best_segment_time_fixes_segment_history() {
    let mut timer = timer();

    let first = TimeSpan::from_seconds(5.0);
    timer.set_game_time(first);
    timer.split();

    let second = TimeSpan::from_seconds(10.0);
    timer.set_game_time(second);
    timer.split();

    let third = TimeSpan::from_seconds(15.0);
    timer.set_game_time(third);
    timer.split();

    let run = timer.into_run(true);
    let run2 = run.clone();

    // =============================================

    let mut editor = Editor::new(run).unwrap();

    editor.select_timing_method(TimingMethod::GameTime);
    editor.select_only(1);
    editor.active_segment().set_split_time(None);

    // Clearing the second segment's split time should not affect the second
    // segment's best segment time.
    assert_eq!(
        editor.run().segment(1).best_segment_time().game_time,
        Some(second - first)
    );

    let new_best = Some(TimeSpan::from_seconds(7.0));

    editor.active_segment().set_best_segment_time(new_best);

    // Changing the second segment's best segment time from 5.0 to 7.0 after
    // clearing the split time should change all times in the segment history so
    // that none are shorter than 7.0.
    assert_eq!(
        editor
            .run()
            .segment(1)
            .segment_history()
            .iter()
            .next()
            .and_then(|&(_, t)| t.game_time),
        new_best
    );
    // The second segment's best segment time should have changed to 7.0.
    assert_eq!(
        editor.run().segment(1).best_segment_time().game_time,
        new_best
    );

    // =============================================

    editor = Editor::new(run2).unwrap();

    editor.select_timing_method(TimingMethod::GameTime);
    editor.select_only(1);
    editor.active_segment().set_best_segment_time(new_best);

    // Changing the second segment's best segment time from 5.0 to 7.0 without
    // clearing the split time first should keep the segment history unaffected.
    // This is because the PB segment is still 5.0.
    assert_eq!(
        editor
            .run()
            .segment(1)
            .segment_history()
            .iter()
            .next()
            .and_then(|&(_, t)| t.game_time),
        Some(second - first)
    );
    // The second segment's best segment time should also be unaffected. This is
    // because the PB segment is still 5.0.
    assert_eq!(
        editor.run().segment(1).best_segment_time().game_time,
        Some(second - first)
    );
}

#[test]
fn import_pb_into_segment_history() {
    let mut editor = Editor::new(run()).unwrap();
    editor.select_timing_method(TimingMethod::GameTime);

    editor.select_only(0);
    let fake_first = Some(TimeSpan::from_seconds(5.0));
    editor.active_segment().set_split_time(fake_first);

    editor.select_only(1);
    let fake_second = Some(TimeSpan::from_seconds(10.0));
    editor.active_segment().set_split_time(fake_second);

    editor.select_only(2);
    let fake_third = Some(TimeSpan::from_seconds(15.0));
    editor.active_segment().set_split_time(fake_third);

    let run = editor.close();
    let mut timer = Timer::new(run).unwrap();

    timer.start();
    timer.initialize_game_time();
    timer.pause_game_time();

    let real_first = TimeSpan::from_seconds(4.0);
    timer.set_game_time(real_first);
    timer.split();

    let real_second = TimeSpan::from_seconds(9.0);
    timer.set_game_time(real_second);
    timer.split();

    let real_third = TimeSpan::from_seconds(13.0);
    timer.set_game_time(real_third);
    timer.split();

    timer.reset(true);

    let run = timer.run();

    // The previous PB's first segment should be imported into the segment
    // history with a non-positive index. A non-positive index means that it was
    // not done during an actual run.
    assert_eq!(
        run.segment(0)
            .segment_history()
            .get(-1)
            .and_then(|t| t.game_time),
        fake_first
    );
    // The new run's first segment should be imported into the segment history
    // with a positive index. A positive index means that it was done during an
    // actual run.
    assert_eq!(
        run.segment(0)
            .segment_history()
            .get(1)
            .and_then(|t| t.game_time),
        Some(real_first)
    );

    // The previous PB's second segment should not be imported into the segment
    // history. This is because it is a duplicate of the new run's second
    // segment.
    assert_eq!(run.segment(1).segment_history().get(-1), None);
    // The new run's second segment should be imported into the segment history
    // with a positive index.
    assert_eq!(
        run.segment(1)
            .segment_history()
            .get(1)
            .and_then(|t| t.game_time),
        Some(real_second - real_first)
    );

    // The previous PB's third segment should be imported into the segment
    // history with a non-positive index.
    assert_eq!(
        run.segment(2)
            .segment_history()
            .get(-1)
            .and_then(|t| t.game_time),
        catch! { fake_third? - fake_second? }
    );
    // The new run's third segment should be imported into the segment history
    // with a positive index.
    assert_eq!(
        run.segment(2)
            .segment_history()
            .get(1)
            .and_then(|t| t.game_time),
        Some(real_third - real_second)
    );
}

#[test]
fn import_pb_into_segment_history_and_remove_null_values() {
    let mut editor = Editor::new(run()).unwrap();
    editor.select_timing_method(TimingMethod::GameTime);

    editor.select_only(0);
    let fake_first = Some(TimeSpan::from_seconds(5.0));
    editor.active_segment().set_split_time(fake_first);

    editor.select_only(2);
    let fake_third = Some(TimeSpan::from_seconds(15.0));
    editor.active_segment().set_split_time(fake_third);

    let run = editor.close();
    let mut timer = Timer::new(run).unwrap();

    timer.start();
    timer.initialize_game_time();
    timer.pause_game_time();

    let real_first = TimeSpan::from_seconds(4.0);
    timer.set_game_time(real_first);
    timer.split();

    timer.skip_split();

    let real_third = TimeSpan::from_seconds(14.0);
    timer.set_game_time(real_third);
    timer.split();

    timer.reset(true);

    let run = timer.run();

    // The previous PB's first segment should be imported into the segment
    // history with a non-positive index. A non-positive index means that it was
    // not done during an actual run.
    assert_eq!(
        run.segment(0)
            .segment_history()
            .get(-1)
            .and_then(|t| t.game_time),
        fake_first
    );
    // The new run's first segment should be imported into the segment history
    // with a positive index. A positive index means that it was done during an
    // actual run.
    assert_eq!(
        run.segment(0)
            .segment_history()
            .get(1)
            .and_then(|t| t.game_time),
        Some(real_first)
    );

    // The previous PB's second segment should not be imported into the segment
    // history. The second segment's split time was blank for the previous PB,
    // so it is actually a part of a combined segment with the third segment.
    // Since the third segment is a duplicate of the new run's third segment,
    // neither the second nor the third segment should be imported.
    assert_eq!(run.segment(1).segment_history().get(-1), None);
    // The new run's second segment has a blank split time, so a null time
    // should be imported into the segment history with a positive index. This
    // indicates that it is a part of a combined segment with the third segment.
    assert_eq!(
        run.segment(1).segment_history().get(1).map(|t| t.game_time),
        Some(None)
    );

    // The previous PB's third segment should not be imported into the segment
    // history. This is because the third segment is a duplicate of the new
    // run's third segment.
    assert_eq!(run.segment(2).segment_history().get(-1), None);
    // The new run's third segment should be imported into the segment history
    // with a positive index.
    assert_eq!(
        run.segment(2)
            .segment_history()
            .get(1)
            .and_then(|t| t.game_time),
        Some(real_third - real_first)
    );
}

#[test]
fn import_best_segment_with_game_time_usage() {
    let mut timer = timer();

    let first = TimeSpan::from_seconds(5.0);
    timer.set_game_time(first);
    timer.split();

    let run = timer.into_run(true);
    let mut editor = Editor::new(run).unwrap();

    editor.select_timing_method(TimingMethod::GameTime);

    editor.select_only(0);
    let best = Some(TimeSpan::from_seconds(4.0));
    editor.active_segment().set_best_segment_time(best);

    editor.insert_segment_above();

    let history = editor.run().segment(0).segment_history();
    // The newly inserted segment's history should have a null time with a
    // non-positive index. This represents a skipped split for the imported best
    // segment with a time of 4.0.
    assert_eq!(history.get(0).map(|t| t.game_time), Some(None));
    // The newly inserted segment's history should have a null time with a
    // positive index. This represents a skipped split for an actual run with a
    // time of 5.0.
    assert_eq!(history.get(1).map(|t| t.game_time), Some(None));

    let history = editor.run().segment(1).segment_history();
    // The second segment's history should have a time of 4.0 with a
    // non-positive index, which represents the imported best segment.
    assert_eq!(history.get(0).and_then(|t| t.game_time), best);
    // The second segment's history should have a time of 5.0 with a positive
    // index, which represents an actual run.
    assert_eq!(history.get(1).and_then(|t| t.game_time), Some(first));
}

#[test]
fn clears_run_id_when_pbing() {
    let mut timer = timer();

    // Get a PB

    timer.set_current_timing_method(TimingMethod::GameTime);

    let first = TimeSpan::from_seconds(5.0);
    timer.set_game_time(first);
    timer.split();

    let second = TimeSpan::from_seconds(10.0);
    timer.set_game_time(second);
    timer.split();

    let third = TimeSpan::from_seconds(15.0);
    timer.set_game_time(third);
    timer.split();

    let mut run = timer.into_run(true);

    // Set the run id

    assert_eq!(run.metadata().run_id(), "");
    run.metadata_mut().set_run_id("34567");
    assert_eq!(run.metadata().run_id(), "34567");

    // Do a new run, but this time don't pb. Run ID should be the same.

    let mut timer = Timer::new(run).unwrap();
    timer.set_current_timing_method(TimingMethod::GameTime);

    timer.start();
    timer.initialize_game_time();
    timer.pause_game_time();

    let first = TimeSpan::from_seconds(6.0);
    timer.set_game_time(first);
    timer.split();

    let second = TimeSpan::from_seconds(11.0);
    timer.set_game_time(second);
    timer.split();

    let third = TimeSpan::from_seconds(16.0);
    timer.set_game_time(third);
    timer.split();

    timer.reset(true);

    assert_eq!(timer.run().metadata().run_id(), "34567");

    // Do a new run and PB. Run ID should be cleared.

    timer.start();
    timer.initialize_game_time();
    timer.pause_game_time();

    let first = TimeSpan::from_seconds(4.0);
    timer.set_game_time(first);
    timer.split();

    let second = TimeSpan::from_seconds(9.0);
    timer.set_game_time(second);
    timer.split();

    let third = TimeSpan::from_seconds(14.0);
    timer.set_game_time(third);
    timer.split();

    timer.reset(true);

    assert_eq!(timer.run().metadata().run_id(), "");
}
<|endoftext|>


<commit_before>/*!
 * Helpers for headers - Tags
 */

/**
 * Spec helpers for header-tags
 */
pub mod spec {
    use storage::file::header::spec::FileHeaderSpec as FHS;
    use module::helpers::spec::{named_text, named_text_array};

    /**
     * helper for a Header spec for
     *
     *  { "URL": "<Text>" }
     */
    pub fn url_key() -> FHS {
        named_text("URL")
    }

    /**
     * helper for a Header spec for
     *
     *  { "TAGS": [ "<Text>", ... ] }
     */
    pub fn tags_key() -> FHS {
        named_text_array("TAGS")
    }

}

/**
 * Data helpers for header-tags
 */
pub mod data {
    use std::ops::Deref;
    use storage::file::header::data::FileHeaderData as FHD;
    use module::Module;
    use clap::ArgMatches;
    use storage::parser::Parser;
    use storage::parser::FileHeaderParser;

    /**
     * Use a Vec<String> to build a Tag-Array:
     *
     *  [ "<Text>", ... ]
     */
    pub fn build_tag_array(tags: Vec<String>) -> FHD {
        let texttags = tags.into_iter().map(|t| FHD::Text(t.clone())).collect();
        FHD::Array { values: Box::new(texttags) }
    }

    /**
     * Fetch tags from a header, whereas the header looks like this:
     *
     *   { ...,
     *     "TAGS": [ "<Text>", ... ],
     *     ...
     *   }
     *
     * Does no spec verification.
     */
    pub fn get_tags_from_header(header: &FHD) -> Vec<String> {
        let mut tags : Vec<String> = vec![];

        fn match_array(a: &Box<FHD>) -> Vec<String> {
            let mut tags : Vec<String> = vec![];

            match a.deref() {
                &FHD::Array{values: ref vs} => {
                    let values : Vec<FHD> = vs.deref().clone();
                    for value in values {
                        match value {
                            FHD::Text(t) => tags.push(t),
                            _ => warn!("Malformed Header Data: Expected Text, found non-Text"),
                        }
                    }
                }
                _ => warn!("Malformed Header Data: Expected Array, found non-Array"),
            }

            tags
        }

        match header {
            &FHD::Map{keys: ref ks} => {
                let keys : Vec<FHD> = ks.clone();
                for key in keys {
                    match key {
                        FHD::Key{name: ref name, value: ref v} => {
                            if name == "TAGS" {
                                return match_array(v)
                            }
                        },
                        _ => warn!("Malformed Header Data: Expected Key, found non-Key"),
                    }
                }
            },
            _ => warn!("Malformed Header Data: Expected Map, found non-Map"),
        }

        tags
    }

    /**
     * Helper function to alter the tags in a file
     */
    pub fn alter_tags_in_files<HP, F, R>(m: &Module,
                                     matches: &ArgMatches,
                                     parser: &Parser<HP>,
                                     generate_new_tags: F,
                                     rebuild_header: R) -> bool
        where HP: FileHeaderParser,
              F:  Fn(Vec<String>, &Vec<String>) -> Vec<String>,
              R:  Fn(&FHD, Vec<String>) -> Option<FHD>
    {
        use std::process::exit;
        use module::helpers::cli::create_tag_filter;
        use module::helpers::cli::create_hash_filter;
        use module::helpers::cli::create_text_header_field_grep_filter;
        use module::helpers::cli::create_content_grep_filter;
        use module::helpers::cli::CliFileFilter;

        let cli_tags = matches.value_of("tags")
                          .map(|ts| {
                            ts.split(",")
                              .map(String::from)
                              .collect::<Vec<String>>()
                          })
                          .unwrap_or(vec![]);

        let filter = {
            let hash_filter = create_hash_filter(matches, "with:id", false);
            let text_filter = create_text_header_field_grep_filter(matches, "with_match", "URL", false);
            let tags_filter = create_tag_filter(matches, "with_tags", false);
            hash_filter.or(Box::new(text_filter)).or(Box::new(tags_filter))
        };

        m.runtime()
            .store()
            .load_for_module(m, &parser)
            .into_iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("Alter tags in file: {:?}", file);

                let hdr = {
                    let f = file.deref().borrow();
                    f.header().clone()
                };

                debug!("Tags:...");
                let old_tags = get_tags_from_header(&hdr);
                debug!("    old_tags = {:?}", &old_tags);
                debug!("    cli_tags = {:?}", &cli_tags);

                let new_tags = generate_new_tags(old_tags, &cli_tags);
                debug!("    new_tags = {:?}", &new_tags);

                let new_header = rebuild_header(&hdr, new_tags)
                    .unwrap_or_else(|| {
                        error!("Could not rebuild header for file");
                        exit(1);
                    });
                {
                    let mut f_mut = file.deref().borrow_mut();
                    f_mut.set_header(new_header);
                }

                m.runtime().store().persist(&parser, file);
                true
            })
            .all(|x| x)
    }

}

<commit_msg>Remove unneeded Keyword "mut"<commit_after>/*!
 * Helpers for headers - Tags
 */

/**
 * Spec helpers for header-tags
 */
pub mod spec {
    use storage::file::header::spec::FileHeaderSpec as FHS;
    use module::helpers::spec::{named_text, named_text_array};

    /**
     * helper for a Header spec for
     *
     *  { "URL": "<Text>" }
     */
    pub fn url_key() -> FHS {
        named_text("URL")
    }

    /**
     * helper for a Header spec for
     *
     *  { "TAGS": [ "<Text>", ... ] }
     */
    pub fn tags_key() -> FHS {
        named_text_array("TAGS")
    }

}

/**
 * Data helpers for header-tags
 */
pub mod data {
    use std::ops::Deref;
    use storage::file::header::data::FileHeaderData as FHD;
    use module::Module;
    use clap::ArgMatches;
    use storage::parser::Parser;
    use storage::parser::FileHeaderParser;

    /**
     * Use a Vec<String> to build a Tag-Array:
     *
     *  [ "<Text>", ... ]
     */
    pub fn build_tag_array(tags: Vec<String>) -> FHD {
        let texttags = tags.into_iter().map(|t| FHD::Text(t.clone())).collect();
        FHD::Array { values: Box::new(texttags) }
    }

    /**
     * Fetch tags from a header, whereas the header looks like this:
     *
     *   { ...,
     *     "TAGS": [ "<Text>", ... ],
     *     ...
     *   }
     *
     * Does no spec verification.
     */
    pub fn get_tags_from_header(header: &FHD) -> Vec<String> {
        let tags : Vec<String> = vec![];

        fn match_array(a: &Box<FHD>) -> Vec<String> {
            let mut tags : Vec<String> = vec![];

            match a.deref() {
                &FHD::Array{values: ref vs} => {
                    let values : Vec<FHD> = vs.deref().clone();
                    for value in values {
                        match value {
                            FHD::Text(t) => tags.push(t),
                            _ => warn!("Malformed Header Data: Expected Text, found non-Text"),
                        }
                    }
                }
                _ => warn!("Malformed Header Data: Expected Array, found non-Array"),
            }

            tags
        }

        match header {
            &FHD::Map{keys: ref ks} => {
                let keys : Vec<FHD> = ks.clone();
                for key in keys {
                    match key {
                        FHD::Key{name: ref name, value: ref v} => {
                            if name == "TAGS" {
                                return match_array(v)
                            }
                        },
                        _ => warn!("Malformed Header Data: Expected Key, found non-Key"),
                    }
                }
            },
            _ => warn!("Malformed Header Data: Expected Map, found non-Map"),
        }

        tags
    }

    /**
     * Helper function to alter the tags in a file
     */
    pub fn alter_tags_in_files<HP, F, R>(m: &Module,
                                     matches: &ArgMatches,
                                     parser: &Parser<HP>,
                                     generate_new_tags: F,
                                     rebuild_header: R) -> bool
        where HP: FileHeaderParser,
              F:  Fn(Vec<String>, &Vec<String>) -> Vec<String>,
              R:  Fn(&FHD, Vec<String>) -> Option<FHD>
    {
        use std::process::exit;
        use module::helpers::cli::create_tag_filter;
        use module::helpers::cli::create_hash_filter;
        use module::helpers::cli::create_text_header_field_grep_filter;
        use module::helpers::cli::create_content_grep_filter;
        use module::helpers::cli::CliFileFilter;

        let cli_tags = matches.value_of("tags")
                          .map(|ts| {
                            ts.split(",")
                              .map(String::from)
                              .collect::<Vec<String>>()
                          })
                          .unwrap_or(vec![]);

        let filter = {
            let hash_filter = create_hash_filter(matches, "with:id", false);
            let text_filter = create_text_header_field_grep_filter(matches, "with_match", "URL", false);
            let tags_filter = create_tag_filter(matches, "with_tags", false);
            hash_filter.or(Box::new(text_filter)).or(Box::new(tags_filter))
        };

        m.runtime()
            .store()
            .load_for_module(m, &parser)
            .into_iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("Alter tags in file: {:?}", file);

                let hdr = {
                    let f = file.deref().borrow();
                    f.header().clone()
                };

                debug!("Tags:...");
                let old_tags = get_tags_from_header(&hdr);
                debug!("    old_tags = {:?}", &old_tags);
                debug!("    cli_tags = {:?}", &cli_tags);

                let new_tags = generate_new_tags(old_tags, &cli_tags);
                debug!("    new_tags = {:?}", &new_tags);

                let new_header = rebuild_header(&hdr, new_tags)
                    .unwrap_or_else(|| {
                        error!("Could not rebuild header for file");
                        exit(1);
                    });
                {
                    let mut f_mut = file.deref().borrow_mut();
                    f_mut.set_header(new_header);
                }

                m.runtime().store().persist(&parser, file);
                true
            })
            .all(|x| x)
    }

}

<|endoftext|>


<commit_before>//! Traits giving structural informations on linear algebra objects or the space they live in.

use std::num::Zero;
use std::slice::{Items, MutItems};
use traits::operations::{RMul, LMul, Axpy};
use traits::geometry::{Dot, Norm, Orig};

/// Traits of objects which can be created from an object of type `T`.
pub trait Cast<T> {
    /// Converts an element of type `T` to an element of type `Self`.
    fn from(t: T) -> Self;
}

/// Trait of matrices.
///
/// A matrix has rows and columns and are able to multiply them.
pub trait Mat<R, C> : Row<R> + Col<C> + RMul<R> + LMul<C> { }

impl<M: Row<R> + Col<C> + RMul<R> + LMul<C>, R, C> Mat<R, C> for M {
}

/// Trait for constructing the identity matrix
pub trait Eye {
    /// Return the identity matrix of specified dimension
    fn new_identity(dim: uint) -> Self;
}

// XXX: we keep ScalarAdd and ScalarSub here to avoid trait impl conflict (overriding) between the
// different Add/Sub traits. This is _so_ unfortunate…

// FIXME: return an iterator instead
/// Traits of objects which can form a basis (typically vectors).
pub trait Basis {
    /// Iterates through the canonical basis of the space in which this object lives.
    fn canonical_basis(|Self| -> bool);

    /// Iterates through a basis of the subspace orthogonal to `self`.
    fn orthonormal_subspace_basis(&Self, |Self| -> bool);
}

/// Trait to access rows of a matrix or a vector.
pub trait Row<R> {
    /// The number of column of `self`.
    fn nrows(&self) -> uint;
    /// Reads the `i`-th row of `self`.
    fn row(&self, i: uint) -> R;
    /// Writes the `i`-th row of `self`.
    fn set_row(&mut self, i: uint, R);

    // FIXME: add iterators on rows: this could be a very good way to generalize _and_ optimize
    // a lot of operations.
}

/// Trait to access columns of a matrix or vector.
pub trait Col<C> {
    /// The number of column of this matrix or vector.
    fn ncols(&self) -> uint;

    /// Reads the `i`-th column of `self`.
    fn col(&self, i: uint) -> C;

    /// Writes the `i`-th column of `self`.
    fn set_col(&mut self, i: uint, C);

    // FIXME: add iterators on columns: this could be a very good way to generalize _and_ optimize
    // a lot of operations.
}

/// Trait to access part of a column of a matrix
pub trait ColSlice<C> {
    /// Returns a view to a slice of a column of a matrix.
    fn col_slice(&self, col_id: uint, row_start: uint, row_end: uint) -> C;
}

/// Trait to access part of a row of a matrix
pub trait RowSlice<R> {
    /// Returns a view to a slice of a row of a matrix.
    fn row_slice(&self, row_id: uint, col_start: uint, col_end: uint) -> R;
}

/// Trait of objects having a spacial dimension known at compile time.
pub trait Dim {
    /// The dimension of the object.
    fn dim(unused_self: Option<Self>) -> uint;
}

/// Trait to get the diagonal of square matrices.
pub trait Diag<V> {
    /// Creates a new matrix with the given diagonal.
    fn from_diag(diag: &V) -> Self;

    /// Sets the diagonal of this matrix.
    fn set_diag(&mut self, diag: &V);

    /// The diagonal of this matrix.
    fn diag(&self) -> V;
}

// FIXME: this trait should not be on nalgebra.
// however, it is needed because std::ops::Index is (strangely) to poor: it
// does not have a function to set values.
// Also, using Index with tuples crashes.
/// This is a workaround of current Rust limitations.
///
/// It exists because the `Index` trait cannot be used to express write access.
/// Thus, this is the same as the `Index` trait but without the syntactic sugar and with a method
/// to write to a specific index.
pub trait Indexable<Index, Res> {
    /// Reads the `i`-th element of `self`.
    fn at(&self, i: Index) -> Res;
    /// Writes to the `i`-th element of `self`.
    fn set(&mut self, i: Index, Res);
    /// Swaps the `i`-th element of `self` with its `j`-th element.
    fn swap(&mut self, i: Index, j: Index);

    /// Returns the shape of the iterable range.
    fn shape(&self) -> Index;

    /// Reads the `i`-th element of `self`.
    ///
    /// `i` is not checked.
    unsafe fn unsafe_at(&self, i: Index) -> Res;
    /// Writes to the `i`-th element of `self`.
    ///
    /// `i` is not checked.
    unsafe fn unsafe_set(&mut self, i: Index, Res);
}

/// This is a workaround of current Rust limitations.
///
/// Traits of objects which can be iterated through like a vector.
pub trait Iterable<N> {
    /// Gets a vector-like read-only iterator.
    fn iter<'l>(&'l self) -> Items<'l, N>;
}

/// This is a workaround of current Rust limitations.
///
/// Traits of mutable objects which can be iterated through like a vector.
pub trait IterableMut<N> {
    /// Gets a vector-like read-write iterator.
    fn iter_mut<'l>(&'l mut self) -> MutItems<'l, N>;
}

/*
 * Vec related traits.
 */
/// Trait that relates a point of an affine space to a vector of the associated vector space.
#[deprecated = "This will be removed in the future. Use point + vector operations instead."]
pub trait VecAsPnt<P> {
    /// Converts this point to its associated vector.
    fn to_pnt(self) -> P;

    /// Converts a reference to this point to a reference to its associated vector.
    fn as_pnt<'a>(&'a self) -> &'a P;
}

/// Trait grouping most common operations on vectors.
pub trait AnyVec<N>: Dim + Sub<Self, Self> + Add<Self, Self> + Neg<Self> + Zero + PartialEq + Mul<N, Self>
                     + Div<N, Self> + Dot<N> + Axpy<N> + Basis {
}

/// Trait of vector with components implementing the `Float` trait.
pub trait FloatVec<N: Float>: AnyVec<N> + Norm<N> {
}

impl<N, V: Dim + Sub<V, V> + Add<V, V> + Neg<V> + Zero + PartialEq + Mul<N, V> + Div<N, V> + Dot<N> + Axpy<N> + Basis>
AnyVec<N> for V { }

impl<N: Float, V: AnyVec<N> + Norm<N>> FloatVec<N> for V { }

/*
 * Pnt related traits.
 */
/// Trait that relates a point of an affine space to a vector of the associated vector space.
pub trait PntAsVec<V> {
    /// Converts this point to its associated vector.
    fn to_vec(self) -> V;

    /// Converts a reference to this point to a reference to its associated vector.
    fn as_vec<'a>(&'a self) -> &'a V;

    // NOTE: this is used in some places to overcome some limitations untill the trait reform is
    // done on rustc.
    /// Sets the coordinates of this point to match those of a given vector.
    fn set_coords(&mut self, coords: V);
}

/// Trait grouping most common operations on points.
// XXX: the vector space element `V` should be an associated type. Though this would prevent V from
// having bounds (they are not supported yet). So, for now, we will just use a type parameter.
pub trait AnyPnt<N, V>:
          PntAsVec<V> + Dim + Sub<Self, V> + Orig + Neg<Self> + PartialEq + Mul<N, Self> +
          Div<N, Self> + Add<V, Self> { // FIXME: + Sub<V, Self>
}

/// Trait of points with components implementing the `Float` trait.
pub trait FloatPnt<N: Float, V: Norm<N>>: AnyPnt<N, V> {
    /// Computes the square distance between two points.
    #[inline]
    fn sqdist(a: &Self, b: &Self) -> N {
        Norm::sqnorm(&(*a - *b))
    }

    /// Computes the distance between two points.
    #[inline]
    fn dist(a: &Self, b: &Self) -> N {
        Norm::norm(&(*a - *b))
    }
}

impl<N, V, P: PntAsVec<V> + Dim + Sub<P, V> + Add<V, P> + Orig + Neg<P> + PartialEq + Mul<N, P> + Div<N, P>>
AnyPnt<N, V> for P { }
impl<N: Float, V: Norm<N>, P: AnyPnt<N, V>> FloatPnt<N, V> for P { }
<commit_msg>Make FloatPnt and FloatVec derive from `Index`.<commit_after>//! Traits giving structural informations on linear algebra objects or the space they live in.

use std::num::Zero;
use std::slice::{Items, MutItems};
use traits::operations::{RMul, LMul, Axpy};
use traits::geometry::{Dot, Norm, Orig};

/// Traits of objects which can be created from an object of type `T`.
pub trait Cast<T> {
    /// Converts an element of type `T` to an element of type `Self`.
    fn from(t: T) -> Self;
}

/// Trait of matrices.
///
/// A matrix has rows and columns and are able to multiply them.
pub trait Mat<R, C> : Row<R> + Col<C> + RMul<R> + LMul<C> { }

impl<M: Row<R> + Col<C> + RMul<R> + LMul<C>, R, C> Mat<R, C> for M {
}

/// Trait for constructing the identity matrix
pub trait Eye {
    /// Return the identity matrix of specified dimension
    fn new_identity(dim: uint) -> Self;
}

// XXX: we keep ScalarAdd and ScalarSub here to avoid trait impl conflict (overriding) between the
// different Add/Sub traits. This is _so_ unfortunate…

// FIXME: return an iterator instead
/// Traits of objects which can form a basis (typically vectors).
pub trait Basis {
    /// Iterates through the canonical basis of the space in which this object lives.
    fn canonical_basis(|Self| -> bool);

    /// Iterates through a basis of the subspace orthogonal to `self`.
    fn orthonormal_subspace_basis(&Self, |Self| -> bool);
}

/// Trait to access rows of a matrix or a vector.
pub trait Row<R> {
    /// The number of column of `self`.
    fn nrows(&self) -> uint;
    /// Reads the `i`-th row of `self`.
    fn row(&self, i: uint) -> R;
    /// Writes the `i`-th row of `self`.
    fn set_row(&mut self, i: uint, R);

    // FIXME: add iterators on rows: this could be a very good way to generalize _and_ optimize
    // a lot of operations.
}

/// Trait to access columns of a matrix or vector.
pub trait Col<C> {
    /// The number of column of this matrix or vector.
    fn ncols(&self) -> uint;

    /// Reads the `i`-th column of `self`.
    fn col(&self, i: uint) -> C;

    /// Writes the `i`-th column of `self`.
    fn set_col(&mut self, i: uint, C);

    // FIXME: add iterators on columns: this could be a very good way to generalize _and_ optimize
    // a lot of operations.
}

/// Trait to access part of a column of a matrix
pub trait ColSlice<C> {
    /// Returns a view to a slice of a column of a matrix.
    fn col_slice(&self, col_id: uint, row_start: uint, row_end: uint) -> C;
}

/// Trait to access part of a row of a matrix
pub trait RowSlice<R> {
    /// Returns a view to a slice of a row of a matrix.
    fn row_slice(&self, row_id: uint, col_start: uint, col_end: uint) -> R;
}

/// Trait of objects having a spacial dimension known at compile time.
pub trait Dim {
    /// The dimension of the object.
    fn dim(unused_self: Option<Self>) -> uint;
}

/// Trait to get the diagonal of square matrices.
pub trait Diag<V> {
    /// Creates a new matrix with the given diagonal.
    fn from_diag(diag: &V) -> Self;

    /// Sets the diagonal of this matrix.
    fn set_diag(&mut self, diag: &V);

    /// The diagonal of this matrix.
    fn diag(&self) -> V;
}

// FIXME: this trait should not be on nalgebra.
// however, it is needed because std::ops::Index is (strangely) to poor: it
// does not have a function to set values.
// Also, using Index with tuples crashes.
/// This is a workaround of current Rust limitations.
///
/// It exists because the `Index` trait cannot be used to express write access.
/// Thus, this is the same as the `Index` trait but without the syntactic sugar and with a method
/// to write to a specific index.
pub trait Indexable<Index, Res> {
    #[deprecated = "use the Index `[]` overloaded operator instead"]
    /// Reads the `i`-th element of `self`.
    fn at(&self, i: Index) -> Res;
    #[deprecated = "use the IndexMut `[]` overloaded operator instead"]
    /// Writes to the `i`-th element of `self`.
    fn set(&mut self, i: Index, Res);
    /// Swaps the `i`-th element of `self` with its `j`-th element.
    fn swap(&mut self, i: Index, j: Index);

    /// Returns the shape of the iterable range.
    fn shape(&self) -> Index;

    /// Reads the `i`-th element of `self`.
    ///
    /// `i` is not checked.
    unsafe fn unsafe_at(&self, i: Index) -> Res;
    /// Writes to the `i`-th element of `self`.
    ///
    /// `i` is not checked.
    unsafe fn unsafe_set(&mut self, i: Index, Res);
}

/// This is a workaround of current Rust limitations.
///
/// Traits of objects which can be iterated through like a vector.
pub trait Iterable<N> {
    /// Gets a vector-like read-only iterator.
    fn iter<'l>(&'l self) -> Items<'l, N>;
}

/// This is a workaround of current Rust limitations.
///
/// Traits of mutable objects which can be iterated through like a vector.
pub trait IterableMut<N> {
    /// Gets a vector-like read-write iterator.
    fn iter_mut<'l>(&'l mut self) -> MutItems<'l, N>;
}

/*
 * Vec related traits.
 */
/// Trait that relates a point of an affine space to a vector of the associated vector space.
#[deprecated = "This will be removed in the future. Use point + vector operations instead."]
pub trait VecAsPnt<P> {
    /// Converts this point to its associated vector.
    fn to_pnt(self) -> P;

    /// Converts a reference to this point to a reference to its associated vector.
    fn as_pnt<'a>(&'a self) -> &'a P;
}

/// Trait grouping most common operations on vectors.
pub trait AnyVec<N>: Dim + Sub<Self, Self> + Add<Self, Self> + Neg<Self> + Zero + PartialEq +
                     Mul<N, Self> + Div<N, Self> + Dot<N> + Axpy<N> + Basis + Index<uint, N> {
}

/// Trait of vector with components implementing the `Float` trait.
pub trait FloatVec<N: Float>: AnyVec<N> + Norm<N> {
}

impl<N, V> AnyVec<N> for V
    where V: Dim + Sub<V, V> + Add<V, V> + Neg<V> + Zero + PartialEq + Mul<N, V> + Div<N, V> +
             Dot<N> + Axpy<N> + Basis + Index<uint, N> {
}

impl<N: Float, V: AnyVec<N> + Norm<N>> FloatVec<N> for V { }

/*
 * Pnt related traits.
 */
/// Trait that relates a point of an affine space to a vector of the associated vector space.
pub trait PntAsVec<V> {
    /// Converts this point to its associated vector.
    fn to_vec(self) -> V;

    /// Converts a reference to this point to a reference to its associated vector.
    fn as_vec<'a>(&'a self) -> &'a V;

    // NOTE: this is used in some places to overcome some limitations untill the trait reform is
    // done on rustc.
    /// Sets the coordinates of this point to match those of a given vector.
    fn set_coords(&mut self, coords: V);
}

/// Trait grouping most common operations on points.
// XXX: the vector space element `V` should be an associated type. Though this would prevent V from
// having bounds (they are not supported yet). So, for now, we will just use a type parameter.
pub trait AnyPnt<N, V>:
          PntAsVec<V> + Dim + Sub<Self, V> + Orig + Neg<Self> + PartialEq + Mul<N, Self> +
          Div<N, Self> + Add<V, Self> + Axpy<N> + Index<uint, N> { // FIXME: + Sub<V, Self>
}

/// Trait of points with components implementing the `Float` trait.
pub trait FloatPnt<N: Float, V: Norm<N>>: AnyPnt<N, V> {
    /// Computes the square distance between two points.
    #[inline]
    fn sqdist(a: &Self, b: &Self) -> N {
        Norm::sqnorm(&(*a - *b))
    }

    /// Computes the distance between two points.
    #[inline]
    fn dist(a: &Self, b: &Self) -> N {
        Norm::norm(&(*a - *b))
    }
}

impl<N, V, P> AnyPnt<N, V> for P
    where P: PntAsVec<V> + Dim + Sub<P, V> + Add<V, P> + Orig + Neg<P> + PartialEq + Mul<N, P> +
             Div<N, P> + Axpy<N> + Index<uint, N> {
}

impl<N, V, P> FloatPnt<N, V> for P
    where N: Float,
          V: Norm<N>,
          P: AnyPnt<N, V> {
}
<|endoftext|>


<commit_before>//! Random access inspection of the results of a dataflow analysis.

use std::borrow::Borrow;
use std::cmp::Ordering;

use rustc_index::bit_set::BitSet;
use rustc_middle::mir::{self, BasicBlock, Location};

use super::{Analysis, Direction, Effect, EffectIndex, Results};

/// A `ResultsCursor` that borrows the underlying `Results`.
pub type ResultsRefCursor<'a, 'mir, 'tcx, A> = ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;

/// Allows random access inspection of the results of a dataflow analysis.
///
/// This cursor only has linear performance within a basic block when its statements are visited in
/// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are
/// visited in *reverse* order—performance will be quadratic in the number of statements in the
/// block. The order in which basic blocks are inspected has no impact on performance.
///
/// A `ResultsCursor` can either own (the default) or borrow the dataflow results it inspects. The
/// type of ownership is determined by `R` (see `ResultsRefCursor` above).
pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>>
where
    A: Analysis<'tcx>,
{
    body: &'mir mir::Body<'tcx>,
    results: R,
    state: BitSet<A::Idx>,

    pos: CursorPosition,

    /// Indicates that `state` has been modified with a custom effect.
    ///
    /// When this flag is set, we need to reset to an entry set before doing a seek.
    state_needs_reset: bool,
}

impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
where
    A: Analysis<'tcx>,
    R: Borrow<Results<'tcx, A>>,
{
    /// Returns a new cursor that can inspect `results`.
    pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
        let bits_per_block = results.borrow().entry_set_for_block(mir::START_BLOCK).domain_size();

        ResultsCursor {
            body,
            results,

            // Initialize to an empty `BitSet` and set `state_needs_reset` to tell the cursor that
            // it needs to reset to block entry before the first seek. The cursor position is
            // immaterial.
            state_needs_reset: true,
            state: BitSet::new_empty(bits_per_block),
            pos: CursorPosition::block_entry(mir::START_BLOCK),
        }
    }

    pub fn body(&self) -> &'mir mir::Body<'tcx> {
        self.body
    }

    /// Returns the `Analysis` used to generate the underlying results.
    pub fn analysis(&self) -> &A {
        &self.results.borrow().analysis
    }

    /// Returns the dataflow state at the current location.
    pub fn get(&self) -> &BitSet<A::Idx> {
        &self.state
    }

    /// Returns `true` if the dataflow state at the current location contains the given element.
    ///
    /// Shorthand for `self.get().contains(elem)`
    pub fn contains(&self, elem: A::Idx) -> bool {
        self.state.contains(elem)
    }

    /// Resets the cursor to hold the dataflow state for the given basic block at fixpoint.
    ///
    /// For forward dataflow analyses, this is the dataflow state prior to the first statement.
    ///
    /// For backward dataflow analyses, this is the dataflow state after the terminator.
    pub(super) fn seek_to_block_entry(&mut self, block: BasicBlock) {
        self.state.overwrite(&self.results.borrow().entry_set_for_block(block));
        self.pos = CursorPosition::block_entry(block);
        self.state_needs_reset = false;
    }

    /// Resets the cursor to hold the state at the entry to the given block.
    ///
    /// For forward analyses, this is the block's state at fixpoint.
    ///
    /// For backward analyses, this is the state that will be propagated to its
    /// predecessors (ignoring edge-specific effects).
    pub fn seek_to_block_start(&mut self, block: BasicBlock) {
        if A::Direction::is_forward() {
            self.seek_to_block_entry(block)
        } else {
            self.seek_after(Location { block, statement_index: 0 }, Effect::Primary)
        }
    }

    /// Resets the cursor to hold the state at the exit of the given block.
    ///
    /// For backward analyses, this is the block's state at fixpoint.
    ///
    /// For forward analyses, this is the state that will be propagated to its
    /// successors (ignoring edge-specific effects).
    pub fn seek_to_block_end(&mut self, block: BasicBlock) {
        if A::Direction::is_backward() {
            self.seek_to_block_entry(block)
        } else {
            self.seek_after(self.body.terminator_loc(block), Effect::Primary)
        }
    }

    /// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is
    /// applied.
    ///
    /// The "before" effect at the target location *will be* applied.
    pub fn seek_before_primary_effect(&mut self, target: Location) {
        self.seek_after(target, Effect::Before)
    }

    /// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is
    /// applied.
    ///
    /// The "before" effect at the target location will be applied as well.
    pub fn seek_after_primary_effect(&mut self, target: Location) {
        self.seek_after(target, Effect::Primary)
    }

    fn seek_after(&mut self, target: Location, effect: Effect) {
        assert!(target <= self.body.terminator_loc(target.block));

        // Reset to the entry of the target block if any of the following are true:
        //   - A custom effect has been applied to the cursor state.
        //   - We are in a different block than the target.
        //   - We are in the same block but have advanced past the target effect.
        if self.state_needs_reset || self.pos.block != target.block {
            self.seek_to_block_entry(target.block);
        } else if let Some(curr_effect) = self.pos.curr_effect_index {
            let mut ord = curr_effect.statement_index.cmp(&target.statement_index);
            if A::Direction::is_backward() {
                ord = ord.reverse()
            }

            match ord.then_with(|| curr_effect.effect.cmp(&effect)) {
                Ordering::Equal => return,
                Ordering::Greater => self.seek_to_block_entry(target.block),
                Ordering::Less => {}
            }
        }

        // At this point, the cursor is in the same block as the target location at an earlier
        // statement.
        debug_assert_eq!(target.block, self.pos.block);

        let block_data = &self.body[target.block];
        let next_effect = if A::Direction::is_forward() {
            #[rustfmt::skip]
            self.pos.curr_effect_index.map_or_else(
                || Effect::Before.at_index(0),
                EffectIndex::next_in_forward_order,
            )
        } else {
            self.pos.curr_effect_index.map_or_else(
                || Effect::Before.at_index(block_data.statements.len()),
                EffectIndex::next_in_backward_order,
            )
        };

        let analysis = &self.results.borrow().analysis;
        let target_effect_index = effect.at_index(target.statement_index);

        A::Direction::apply_effects_in_range(
            analysis,
            &mut self.state,
            target.block,
            block_data,
            next_effect..=target_effect_index,
        );

        self.pos =
            CursorPosition { block: target.block, curr_effect_index: Some(target_effect_index) };
    }

    /// Applies `f` to the cursor's internal state.
    ///
    /// This can be used, e.g., to apply the call return effect directly to the cursor without
    /// creating an extra copy of the dataflow state.
    pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut BitSet<A::Idx>)) {
        f(&self.results.borrow().analysis, &mut self.state);
        self.state_needs_reset = true;
    }
}

#[derive(Clone, Copy, Debug)]
struct CursorPosition {
    block: BasicBlock,
    curr_effect_index: Option<EffectIndex>,
}

impl CursorPosition {
    fn block_entry(block: BasicBlock) -> CursorPosition {
        CursorPosition { block, curr_effect_index: None }
    }
}
<commit_msg>Use agreed upon terminology in cursor docs<commit_after>//! Random access inspection of the results of a dataflow analysis.

use std::borrow::Borrow;
use std::cmp::Ordering;

use rustc_index::bit_set::BitSet;
use rustc_middle::mir::{self, BasicBlock, Location};

use super::{Analysis, Direction, Effect, EffectIndex, Results};

/// A `ResultsCursor` that borrows the underlying `Results`.
pub type ResultsRefCursor<'a, 'mir, 'tcx, A> = ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;

/// Allows random access inspection of the results of a dataflow analysis.
///
/// This cursor only has linear performance within a basic block when its statements are visited in
/// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are
/// visited in *reverse* order—performance will be quadratic in the number of statements in the
/// block. The order in which basic blocks are inspected has no impact on performance.
///
/// A `ResultsCursor` can either own (the default) or borrow the dataflow results it inspects. The
/// type of ownership is determined by `R` (see `ResultsRefCursor` above).
pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>>
where
    A: Analysis<'tcx>,
{
    body: &'mir mir::Body<'tcx>,
    results: R,
    state: BitSet<A::Idx>,

    pos: CursorPosition,

    /// Indicates that `state` has been modified with a custom effect.
    ///
    /// When this flag is set, we need to reset to an entry set before doing a seek.
    state_needs_reset: bool,
}

impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
where
    A: Analysis<'tcx>,
    R: Borrow<Results<'tcx, A>>,
{
    /// Returns a new cursor that can inspect `results`.
    pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
        let bits_per_block = results.borrow().entry_set_for_block(mir::START_BLOCK).domain_size();

        ResultsCursor {
            body,
            results,

            // Initialize to an empty `BitSet` and set `state_needs_reset` to tell the cursor that
            // it needs to reset to block entry before the first seek. The cursor position is
            // immaterial.
            state_needs_reset: true,
            state: BitSet::new_empty(bits_per_block),
            pos: CursorPosition::block_entry(mir::START_BLOCK),
        }
    }

    pub fn body(&self) -> &'mir mir::Body<'tcx> {
        self.body
    }

    /// Returns the `Analysis` used to generate the underlying results.
    pub fn analysis(&self) -> &A {
        &self.results.borrow().analysis
    }

    /// Returns the dataflow state at the current location.
    pub fn get(&self) -> &BitSet<A::Idx> {
        &self.state
    }

    /// Returns `true` if the dataflow state at the current location contains the given element.
    ///
    /// Shorthand for `self.get().contains(elem)`
    pub fn contains(&self, elem: A::Idx) -> bool {
        self.state.contains(elem)
    }

    /// Resets the cursor to hold the entry set for the given basic block.
    ///
    /// For forward dataflow analyses, this is the dataflow state prior to the first statement.
    ///
    /// For backward dataflow analyses, this is the dataflow state after the terminator.
    pub(super) fn seek_to_block_entry(&mut self, block: BasicBlock) {
        self.state.overwrite(&self.results.borrow().entry_set_for_block(block));
        self.pos = CursorPosition::block_entry(block);
        self.state_needs_reset = false;
    }

    /// Resets the cursor to hold the state prior to the first statement in a basic block.
    ///
    /// For forward analyses, this is the entry set for the given block.
    ///
    /// For backward analyses, this is the state that will be propagated to its
    /// predecessors (ignoring edge-specific effects).
    pub fn seek_to_block_start(&mut self, block: BasicBlock) {
        if A::Direction::is_forward() {
            self.seek_to_block_entry(block)
        } else {
            self.seek_after(Location { block, statement_index: 0 }, Effect::Primary)
        }
    }

    /// Resets the cursor to hold the state after the terminator in a basic block.
    ///
    /// For backward analyses, this is the entry set for the given block.
    ///
    /// For forward analyses, this is the state that will be propagated to its
    /// successors (ignoring edge-specific effects).
    pub fn seek_to_block_end(&mut self, block: BasicBlock) {
        if A::Direction::is_backward() {
            self.seek_to_block_entry(block)
        } else {
            self.seek_after(self.body.terminator_loc(block), Effect::Primary)
        }
    }

    /// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is
    /// applied.
    ///
    /// The "before" effect at the target location *will be* applied.
    pub fn seek_before_primary_effect(&mut self, target: Location) {
        self.seek_after(target, Effect::Before)
    }

    /// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is
    /// applied.
    ///
    /// The "before" effect at the target location will be applied as well.
    pub fn seek_after_primary_effect(&mut self, target: Location) {
        self.seek_after(target, Effect::Primary)
    }

    fn seek_after(&mut self, target: Location, effect: Effect) {
        assert!(target <= self.body.terminator_loc(target.block));

        // Reset to the entry of the target block if any of the following are true:
        //   - A custom effect has been applied to the cursor state.
        //   - We are in a different block than the target.
        //   - We are in the same block but have advanced past the target effect.
        if self.state_needs_reset || self.pos.block != target.block {
            self.seek_to_block_entry(target.block);
        } else if let Some(curr_effect) = self.pos.curr_effect_index {
            let mut ord = curr_effect.statement_index.cmp(&target.statement_index);
            if A::Direction::is_backward() {
                ord = ord.reverse()
            }

            match ord.then_with(|| curr_effect.effect.cmp(&effect)) {
                Ordering::Equal => return,
                Ordering::Greater => self.seek_to_block_entry(target.block),
                Ordering::Less => {}
            }
        }

        // At this point, the cursor is in the same block as the target location at an earlier
        // statement.
        debug_assert_eq!(target.block, self.pos.block);

        let block_data = &self.body[target.block];
        let next_effect = if A::Direction::is_forward() {
            #[rustfmt::skip]
            self.pos.curr_effect_index.map_or_else(
                || Effect::Before.at_index(0),
                EffectIndex::next_in_forward_order,
            )
        } else {
            self.pos.curr_effect_index.map_or_else(
                || Effect::Before.at_index(block_data.statements.len()),
                EffectIndex::next_in_backward_order,
            )
        };

        let analysis = &self.results.borrow().analysis;
        let target_effect_index = effect.at_index(target.statement_index);

        A::Direction::apply_effects_in_range(
            analysis,
            &mut self.state,
            target.block,
            block_data,
            next_effect..=target_effect_index,
        );

        self.pos =
            CursorPosition { block: target.block, curr_effect_index: Some(target_effect_index) };
    }

    /// Applies `f` to the cursor's internal state.
    ///
    /// This can be used, e.g., to apply the call return effect directly to the cursor without
    /// creating an extra copy of the dataflow state.
    pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut BitSet<A::Idx>)) {
        f(&self.results.borrow().analysis, &mut self.state);
        self.state_needs_reset = true;
    }
}

#[derive(Clone, Copy, Debug)]
struct CursorPosition {
    block: BasicBlock,
    curr_effect_index: Option<EffectIndex>,
}

impl CursorPosition {
    fn block_entry(block: BasicBlock) -> CursorPosition {
        CursorPosition { block, curr_effect_index: None }
    }
}
<|endoftext|>


<commit_before>use std::env;

use crate::spec::{FramePointer, LldFlavor, SplitDebuginfo, TargetOptions};

pub fn opts(os: &str) -> TargetOptions {
    // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
    // either the linker will complain if it is used or the binary will end up
    // segfaulting at runtime when run on 10.6. Rust by default supports macOS
    // 10.7+, but there is a standard environment variable,
    // MACOSX_DEPLOYMENT_TARGET, which is used to signal targeting older
    // versions of macOS. For example compiling on 10.10 with
    // MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate
    // warnings about the usage of ELF TLS.
    //
    // Here we detect what version is being requested, defaulting to 10.7. ELF
    // TLS is flagged as enabled if it looks to be supported.
    let version = macos_deployment_target();

    TargetOptions {
        os: os.to_string(),
        vendor: "apple".to_string(),
        // macOS has -dead_strip, which doesn't rely on function_sections
        function_sections: false,
        dynamic_linking: true,
        linker_is_gnu: false,
        executables: true,
        families: vec!["unix".to_string()],
        is_like_osx: true,
        dwarf_version: Some(2),
        frame_pointer: FramePointer::Always,
        has_rpath: true,
        dll_suffix: ".dylib".to_string(),
        archive_format: "darwin".to_string(),
        has_elf_tls: version >= (10, 7),
        abi_return_struct_as_int: true,
        emit_debug_gdb_scripts: false,
        eh_frame_header: false,
        lld_flavor: LldFlavor::Ld64,

        // The historical default for macOS targets is to run `dsymutil` which
        // generates a packed version of debuginfo split from the main file.
        split_debuginfo: SplitDebuginfo::Packed,

        // This environment variable is pretty magical but is intended for
        // producing deterministic builds. This was first discovered to be used
        // by the `ar` tool as a way to control whether or not mtime entries in
        // the archive headers were set to zero or not. It appears that
        // eventually the linker got updated to do the same thing and now reads
        // this environment variable too in recent versions.
        //
        // For some more info see the commentary on #47086
        link_env: vec![("ZERO_AR_DATE".to_string(), "1".to_string())],

        ..Default::default()
    }
}

fn deployment_target(var_name: &str) -> Option<(u32, u32)> {
    let deployment_target = env::var(var_name).ok();
    deployment_target
        .as_ref()
        .and_then(|s| s.split_once('.'))
        .and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
}

fn macos_deployment_target() -> (u32, u32) {
    deployment_target("MACOSX_DEPLOYMENT_TARGET").unwrap_or((10, 7))
}

pub fn macos_llvm_target(arch: &str) -> String {
    let (major, minor) = macos_deployment_target();
    format!("{}-apple-macosx{}.{}.0", arch, major, minor)
}

pub fn macos_link_env_remove() -> Vec<String> {
    let mut env_remove = Vec::with_capacity(2);
    // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which
    // may occur when we're linking a custom build script while targeting iOS for example.
    if let Ok(sdkroot) = env::var("SDKROOT") {
        if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") {
            env_remove.push("SDKROOT".to_string())
        }
    }
    // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
    // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld",
    // although this is apparently ignored when using the linker at "/usr/bin/ld".
    env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".to_string());
    env_remove
}

fn ios_deployment_target() -> (u32, u32) {
    deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
}

pub fn ios_llvm_target(arch: &str) -> String {
    // Modern iOS tooling extracts information about deployment target
    // from LC_BUILD_VERSION. This load command will only be emitted when
    // we build with a version specific `llvm_target`, with the version
    // set high enough. Luckily one LC_BUILD_VERSION is enough, for Xcode
    // to pick it up (since std and core are still built with the fallback
    // of version 7.0 and hence emit the old LC_IPHONE_MIN_VERSION).
    let (major, minor) = ios_deployment_target();
    format!("{}-apple-ios{}.{}.0", arch, major, minor)
}

pub fn ios_sim_llvm_target(arch: &str) -> String {
    let (major, minor) = ios_deployment_target();
    format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
}
<commit_msg>Set the default deployment target for Macos ARM64 to 11.0.<commit_after>use std::env;

use crate::spec::{FramePointer, LldFlavor, SplitDebuginfo, TargetOptions};

pub fn opts(os: &str) -> TargetOptions {
    // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
    // either the linker will complain if it is used or the binary will end up
    // segfaulting at runtime when run on 10.6. Rust by default supports macOS
    // 10.7+, but there is a standard environment variable,
    // MACOSX_DEPLOYMENT_TARGET, which is used to signal targeting older
    // versions of macOS. For example compiling on 10.10 with
    // MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate
    // warnings about the usage of ELF TLS.
    //
    // Here we detect what version is being requested, defaulting to 10.7. ELF
    // TLS is flagged as enabled if it looks to be supported. The architecture
    // only matters for default deployment target which is 11.0 for ARM64 and
    // 10.7 for everything else.
    let has_elf_tls = macos_deployment_target("x86_64") >= (10, 7);

    TargetOptions {
        os: os.to_string(),
        vendor: "apple".to_string(),
        // macOS has -dead_strip, which doesn't rely on function_sections
        function_sections: false,
        dynamic_linking: true,
        linker_is_gnu: false,
        executables: true,
        families: vec!["unix".to_string()],
        is_like_osx: true,
        dwarf_version: Some(2),
        frame_pointer: FramePointer::Always,
        has_rpath: true,
        dll_suffix: ".dylib".to_string(),
        archive_format: "darwin".to_string(),
        has_elf_tls,
        abi_return_struct_as_int: true,
        emit_debug_gdb_scripts: false,
        eh_frame_header: false,
        lld_flavor: LldFlavor::Ld64,

        // The historical default for macOS targets is to run `dsymutil` which
        // generates a packed version of debuginfo split from the main file.
        split_debuginfo: SplitDebuginfo::Packed,

        // This environment variable is pretty magical but is intended for
        // producing deterministic builds. This was first discovered to be used
        // by the `ar` tool as a way to control whether or not mtime entries in
        // the archive headers were set to zero or not. It appears that
        // eventually the linker got updated to do the same thing and now reads
        // this environment variable too in recent versions.
        //
        // For some more info see the commentary on #47086
        link_env: vec![("ZERO_AR_DATE".to_string(), "1".to_string())],

        ..Default::default()
    }
}

fn deployment_target(var_name: &str) -> Option<(u32, u32)> {
    let deployment_target = env::var(var_name).ok();
    deployment_target
        .as_ref()
        .and_then(|s| s.split_once('.'))
        .and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
}

fn macos_default_deployment_target(arch: &str) -> (u32, u32) {
    if arch == "arm64" { (11, 0) } else { (10, 7) }
}

fn macos_deployment_target(arch: &str) -> (u32, u32) {
    deployment_target("MACOSX_DEPLOYMENT_TARGET")
        .unwrap_or_else(|| macos_default_deployment_target(arch))
}

pub fn macos_llvm_target(arch: &str) -> String {
    let (major, minor) = macos_deployment_target(arch);
    format!("{}-apple-macosx{}.{}.0", arch, major, minor)
}

pub fn macos_link_env_remove() -> Vec<String> {
    let mut env_remove = Vec::with_capacity(2);
    // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which
    // may occur when we're linking a custom build script while targeting iOS for example.
    if let Ok(sdkroot) = env::var("SDKROOT") {
        if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") {
            env_remove.push("SDKROOT".to_string())
        }
    }
    // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
    // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld",
    // although this is apparently ignored when using the linker at "/usr/bin/ld".
    env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".to_string());
    env_remove
}

fn ios_deployment_target() -> (u32, u32) {
    deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
}

pub fn ios_llvm_target(arch: &str) -> String {
    // Modern iOS tooling extracts information about deployment target
    // from LC_BUILD_VERSION. This load command will only be emitted when
    // we build with a version specific `llvm_target`, with the version
    // set high enough. Luckily one LC_BUILD_VERSION is enough, for Xcode
    // to pick it up (since std and core are still built with the fallback
    // of version 7.0 and hence emit the old LC_IPHONE_MIN_VERSION).
    let (major, minor) = ios_deployment_target();
    format!("{}-apple-ios{}.{}.0", arch, major, minor)
}

pub fn ios_sim_llvm_target(arch: &str) -> String {
    let (major, minor) = ios_deployment_target();
    format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
}
<|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/. */

//! Generic types for CSS handling of specified and computed values of
//! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position)

use cssparser::Parser;
use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
use values::specified::{LengthOrPercentage, Percentage};

define_css_keyword_enum!{ Keyword:
    "center" => Center,
    "left" => Left,
    "right" => Right,
    "top" => Top,
    "bottom" => Bottom,
    "x-start" => XStart,
    "x-end" => XEnd,
    "y-start" => YStart,
    "y-end" => YEnd
}

impl From<Keyword> for LengthOrPercentage {
    fn from(val: Keyword) -> LengthOrPercentage {
        match val {
            Keyword::Center => LengthOrPercentage::Percentage(Percentage(0.5)),
            Keyword::Left | Keyword::Top => LengthOrPercentage::Percentage(Percentage(0.0)),
            Keyword::Right | Keyword::Bottom => LengthOrPercentage::Percentage(Percentage(1.0)),
            // FIXME(canaltinova): Support logical keywords
            Keyword::XStart | Keyword::YStart => LengthOrPercentage::Percentage(Percentage(0.0)),
            Keyword::XEnd | Keyword::YEnd => LengthOrPercentage::Percentage(Percentage(1.0)),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A generic type for representing horizontal or vertical `<position>` value.
pub struct PositionValue<L> {
    /// Even though this is generic, it's always a `<length-percentage>` value.
    pub position: Option<L>,
    /// A position keyword.
    pub keyword: Option<Keyword>,
}

impl<L: HasViewportPercentage> HasViewportPercentage for PositionValue<L> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        self.position.as_ref().map_or(false, |pos| pos.has_viewport_percentage())
    }
}

impl<L: Parse> PositionValue<L> {
    /// Internal parsing function which (after parsing) checks the keyword with the
    /// given function.
    pub fn parse_internal<F>(context: &ParserContext, input: &mut Parser,
                             mut is_allowed_keyword: F) -> Result<PositionValue<L>, ()>
        where F: FnMut(Keyword) -> bool
    {
        let (mut pos, mut keyword) = (None, None);
        for _ in 0..2 {
            if let Ok(l) = input.try(|i| L::parse(context, i)) {
                if pos.is_some() {
                    return Err(())
                }

                pos = Some(l);
            }

            if let Ok(k) = input.try(Keyword::parse) {
                if keyword.is_some() || !is_allowed_keyword(k) {
                    return Err(())
                }

                keyword = Some(k);
            }
        }

        if pos.is_some() {
            if let Some(Keyword::Center) = keyword {
                return Err(())      // "center" and <length> is not allowed
            }
        } else if keyword.is_none() {
            return Err(())      // at least one value is necessary
        }

        Ok(PositionValue {
            position: pos,
            keyword: keyword,
        })
    }
}

impl<L: ToCss> ToCss for PositionValue<L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        if let Some(keyword) = self.keyword {
            keyword.to_css(dest)?;
        }

        if let Some(ref position) = self.position {
            if self.keyword.is_some() {
                dest.write_str(" ")?;
            }

            position.to_css(dest)?;
        }

        Ok(())
    }
}
<commit_msg>Add generic versions of Position structs<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/. */

//! Generic types for CSS handling of specified and computed values of
//! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position)

use cssparser::Parser;
use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
use values::specified::{LengthOrPercentage, Percentage};

define_css_keyword_enum!{ Keyword:
    "center" => Center,
    "left" => Left,
    "right" => Right,
    "top" => Top,
    "bottom" => Bottom,
    "x-start" => XStart,
    "x-end" => XEnd,
    "y-start" => YStart,
    "y-end" => YEnd
}

impl From<Keyword> for LengthOrPercentage {
    fn from(val: Keyword) -> LengthOrPercentage {
        match val {
            Keyword::Center => LengthOrPercentage::Percentage(Percentage(0.5)),
            Keyword::Left | Keyword::Top => LengthOrPercentage::Percentage(Percentage(0.0)),
            Keyword::Right | Keyword::Bottom => LengthOrPercentage::Percentage(Percentage(1.0)),
            // FIXME(canaltinova): Support logical keywords
            Keyword::XStart | Keyword::YStart => LengthOrPercentage::Percentage(Percentage(0.0)),
            Keyword::XEnd | Keyword::YEnd => LengthOrPercentage::Percentage(Percentage(1.0)),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A generic type for representing horizontal or vertical `<position>` value.
pub struct PositionValue<L> {
    /// Even though this is generic, it's always a `<length-percentage>` value.
    pub position: Option<L>,
    /// A position keyword.
    pub keyword: Option<Keyword>,
}

impl<L: HasViewportPercentage> HasViewportPercentage for PositionValue<L> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        self.position.as_ref().map_or(false, |pos| pos.has_viewport_percentage())
    }
}

impl<L: Parse> PositionValue<L> {
    /// Internal parsing function which (after parsing) checks the keyword with the
    /// given function.
    pub fn parse_internal<F>(context: &ParserContext, input: &mut Parser,
                             mut is_allowed_keyword: F) -> Result<PositionValue<L>, ()>
        where F: FnMut(Keyword) -> bool
    {
        let (mut pos, mut keyword) = (None, None);
        for _ in 0..2 {
            if let Ok(l) = input.try(|i| L::parse(context, i)) {
                if pos.is_some() {
                    return Err(())
                }

                pos = Some(l);
            }

            if let Ok(k) = input.try(Keyword::parse) {
                if keyword.is_some() || !is_allowed_keyword(k) {
                    return Err(())
                }

                keyword = Some(k);
            }
        }

        if pos.is_some() {
            if let Some(Keyword::Center) = keyword {
                return Err(())      // "center" and <length> is not allowed
            }
        } else if keyword.is_none() {
            return Err(())      // at least one value is necessary
        }

        Ok(PositionValue {
            position: pos,
            keyword: keyword,
        })
    }
}

impl<L: ToCss> ToCss for PositionValue<L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        if let Some(keyword) = self.keyword {
            keyword.to_css(dest)?;
        }

        if let Some(ref position) = self.position {
            if self.keyword.is_some() {
                dest.write_str(" ")?;
            }

            position.to_css(dest)?;
        }

        Ok(())
    }
}

#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A generic type for representing horizontal `<position>`
pub struct HorizontalPosition<L>(pub L);

impl<L: ToCss> ToCss for HorizontalPosition<L> {
    #[inline]
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        self.0.to_css(dest)
    }
}

impl<L: HasViewportPercentage> HasViewportPercentage for HorizontalPosition<L> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        self.0.has_viewport_percentage()
    }
}

impl<L: Parse> Parse for HorizontalPosition<PositionValue<L>> {
    #[inline]
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        PositionValue::parse_internal(context, input, |keyword| {
            matches!{ keyword,
                Keyword::Left | Keyword::Right | Keyword::Center |
                Keyword::XStart | Keyword::XEnd
            }
        }).map(HorizontalPosition)
    }
}

#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A generic type for representing vertical `<position>`
pub struct VerticalPosition<L>(pub L);

impl<L: ToCss> ToCss for VerticalPosition<L> {
    #[inline]
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        self.0.to_css(dest)
    }
}

impl<L: HasViewportPercentage> HasViewportPercentage for VerticalPosition<L> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        self.0.has_viewport_percentage()
    }
}

impl<L: Parse> Parse for VerticalPosition<PositionValue<L>> {
    #[inline]
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        PositionValue::parse_internal(context, input, |keyword| {
            matches!{ keyword,
                Keyword::Top | Keyword::Bottom | Keyword::Center |
                Keyword::YStart | Keyword::YEnd
            }
        }).map(VerticalPosition)
    }
}

#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position).
///
/// Note that the horizontal and vertical positions aren't really different types.
/// They're just unit struct wrappers over `LengthOrPercentage`. They should be different
/// because they allow different keywords (for e.g., vertical position doesn't allow
/// `right` or `left` keywords and vice versa).
pub struct Position<H, V> {
    /// The horizontal component of position.
    pub horizontal: H,
    /// The vertical component of position.
    pub vertical: V,
}

/// A generic type for representing positions with keywords.
pub type PositionWithKeyword<L> = Position<HorizontalPosition<L>, VerticalPosition<L>>;

impl<H: HasViewportPercentage, V: HasViewportPercentage> HasViewportPercentage for Position<H, V> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        self.horizontal.has_viewport_percentage() || self.vertical.has_viewport_percentage()
    }
}

impl<L: ToCss> ToCss for Position<L, L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        self.horizontal.to_css(dest)?;
        dest.write_str(" ")?;
        self.vertical.to_css(dest)
    }
}

impl<L: ToCss> ToCss for PositionWithKeyword<PositionValue<L>> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        macro_rules! to_css_with_keyword {
            ($pos:expr, $default:expr) => {
                $pos.keyword.unwrap_or($default).to_css(dest)?;
                if let Some(ref position) = $pos.position {
                    dest.write_str(" ")?;
                    position.to_css(dest)?;
                }
            }
        }

        if (self.horizontal.0.keyword.is_some() && self.horizontal.0.position.is_some()) ||
           (self.vertical.0.keyword.is_some() && self.vertical.0.position.is_some()) {
            to_css_with_keyword!(self.horizontal.0, Keyword::Left);
            dest.write_str(" ")?;
            to_css_with_keyword!(self.vertical.0, Keyword::Top);
            return Ok(())
        }

        self.horizontal.to_css(dest)?;
        dest.write_str(" ")?;
        self.vertical.to_css(dest)
    }
}

impl<H: ToComputedValue, V: ToComputedValue> ToComputedValue for Position<H, V> {
    type ComputedValue = Position<H::ComputedValue, V::ComputedValue>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        Position {
            horizontal: self.horizontal.to_computed_value(context),
            vertical: self.vertical.to_computed_value(context),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        Position {
            horizontal: ToComputedValue::from_computed_value(&computed.horizontal),
            vertical: ToComputedValue::from_computed_value(&computed.vertical),
        }
    }
}
<|endoftext|>