<commit_before>use crate::common::util::*;

// Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'.
// If we are running inside the CI and "needle" is in "stderr" skipping this test is
// considered okay. If we are not inside the CI this calls assert!(result.success).
//
// From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)"
//    whoami: cannot find name for user ID 1001
// id --name: cannot find name for user ID 1001
// id --name: cannot find name for group ID 116
//
// However, when running "id" from within "/bin/bash" it looks fine:
// id: "uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),101(systemd-journal)"
// whoami: "runner"
//
fn skipping_test_is_okay(result: &CmdResult, needle: &str) -> bool {
    if !result.succeeded() {
        println!("result.stdout = {}", result.stdout_str());
        println!("result.stderr = {}", result.stderr_str());
        if is_ci() && result.stderr_str().contains(needle) {
            println!("test skipped:");
            return true;
        } else {
            result.success();
        }
    }
    false
}

fn return_whoami_username() -> String {
    let scene = TestScenario::new("whoami");
    let result = scene.cmd("whoami").run();
    if skipping_test_is_okay(&result, "whoami: cannot find name for user ID") {
        println!("test skipped:");
        return String::from("");
    }

    result.stdout_str().trim().to_string()
}

#[test]
fn test_id() {
    let scene = TestScenario::new(util_name!());

    let result = scene.ucmd().arg("-u").succeeds();
    let uid = result.stdout_str().trim();

    let result = scene.ucmd().run();
    if skipping_test_is_okay(&result, "Could not find uid") {
        return;
    }

    // Verify that the id found by --user/-u exists in the list
    result.stdout_contains(uid);
}

#[test]
fn test_id_from_name() {
    let username = return_whoami_username();
    if username.is_empty() {
        return;
    }

    let scene = TestScenario::new(util_name!());
    let result = scene.ucmd().arg(&username).run();
    if skipping_test_is_okay(&result, "Could not find uid") {
        return;
    }

    let uid = result.stdout_str().trim();

    let result = scene.ucmd().run();
    if skipping_test_is_okay(&result, "Could not find uid") {
        return;
    }

    result
        // Verify that the id found by --user/-u exists in the list
        .stdout_contains(uid)
        // Verify that the username found by whoami exists in the list
        .stdout_contains(username);
}

#[test]
fn test_id_name_from_id() {
    let result = new_ucmd!().arg("-nu").run();

    let username_id = result.stdout_str().trim();

    let username_whoami = return_whoami_username();
    if username_whoami.is_empty() {
        return;
    }

    assert_eq!(username_id, username_whoami);
}

#[test]
fn test_id_pretty_print() {
    let username = return_whoami_username();
    if username.is_empty() {
        return;
    }

    let scene = TestScenario::new(util_name!());
    let result = scene.ucmd().arg("-p").run();
    if result.stdout_str().trim().is_empty() {
        // this fails only on: "MinRustV (ubuntu-latest, feat_os_unix)"
        // `rustc 1.40.0 (73528e339 2019-12-16)`
        // run: /home/runner/work/coreutils/coreutils/target/debug/coreutils id -p
        // thread 'test_id::test_id_pretty_print' panicked at 'Command was expected to succeed.
        // stdout =
        // stderr = ', tests/common/util.rs:157:13
        println!("test skipped:");
        return;
    }

    result.success().stdout_contains(username);
}

#[test]
fn test_id_password_style() {
    let username = return_whoami_username();
    if username.is_empty() {
        return;
    }

    let result = new_ucmd!().arg("-P").succeeds();

    assert!(result.stdout_str().starts_with(&username));
}

#[test]
#[cfg(unix)]
fn test_id_default_format() {
    // TODO: These are the same tests like in test_id_zero but without --zero flag.
}

#[test]
#[cfg(unix)]
fn test_id_zero() {
    let scene = TestScenario::new(util_name!());
    for z_flag in &["-z", "--zero"] {
        for &opt1 in &["--name", "--real"] {
            // id: cannot print only names or real IDs in default format
            let args = [opt1, z_flag];
            scene
                .ucmd()
                .args(&args)
                .fails()
                .stderr_only(expected_result(&args).stderr_str());
            for &opt2 in &["--user", "--group", "--groups"] {
                // u/g/G n/r z
                let args = [opt2, z_flag, opt1];
                let result = scene.ucmd().args(&args).run();
                let expected_result = expected_result(&args);
                result
                    .stdout_is_bytes(expected_result.stdout())
                    .stderr_is_bytes(expected_result.stderr());
            }
        }
        // u/g/G z
        for &opt2 in &["--user", "--group", "--groups"] {
            let args = [opt2, z_flag];
            scene
                .ucmd()
                .args(&args)
                .succeeds()
                .stdout_only_bytes(expected_result(&args).stdout());
        }
    }
}

#[allow(clippy::needless_borrow)]
#[cfg(unix)]
fn expected_result(args: &[&str]) -> CmdResult {
    #[cfg(target_os = "linux")]
    let util_name = util_name!();
    #[cfg(all(unix, not(target_os = "linux")))]
    let util_name = format!("g{}", util_name!());

    let result = TestScenario::new(&util_name)
        .cmd_keepenv(&util_name)
        .env("LANGUAGE", "C")
        .args(args)
        .run();

    let mut _o = 0;
    let mut _e = 0;
    #[cfg(all(unix, not(target_os = "linux")))]
    {
        _o = if result.stdout_str().starts_with(&util_name) {
            1
        } else {
            0
        };
        _e = if result.stderr_str().starts_with(&util_name) {
            1
        } else {
            0
        };
    }

    CmdResult::new(
        Some(result.tmpd()),
        Some(result.code()),
        result.succeeded(),
        &result.stdout()[_o..],
        &result.stderr()[_e..],
    )
}
<commit_msg>id: add more tests for multiple and/or invalid usernames<commit_after>use crate::common::util::*;

// Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'.
//
// From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)"
//    whoami: cannot find name for user ID 1001
// id --name: cannot find name for user ID 1001
// id --name: cannot find name for group ID 116
//
// However, when running "id" from within "/bin/bash" it looks fine:
// id: "uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),101(systemd-journal)"
// whoami: "runner"
//

fn whoami() -> String {
    std::env::var("USER").unwrap_or_else(|e| {
        println!("warning: {}, using \"nobody\" instead", e);
        "nobody".to_string()
    })
}

#[test]
#[cfg(unix)]
fn test_id_no_argument() {
    let result = new_ucmd!().run();
    let expected_result = expected_result(&[]);
    let mut exp_stdout = expected_result.stdout_str().to_string();

    // uu_stid does not support selinux context. Remove 'context' part from exp_stdout:
    let context_offset = expected_result
        .stdout_str()
        .find(" context")
        .unwrap_or(exp_stdout.len());
    exp_stdout.replace_range(context_offset.., "\n");

    result
        .stdout_is(exp_stdout)
        .stderr_is(expected_result.stderr_str())
        .code_is(expected_result.code());
}

#[test]
#[cfg(unix)]
fn test_id_single_user() {
    let args = &[&whoami()[..]];
    let result = new_ucmd!().args(args).run();
    let expected_result = expected_result(args);
    result
        .stdout_is(expected_result.stdout_str())
        .stderr_is(expected_result.stderr_str())
        .code_is(expected_result.code());
}

#[test]
#[cfg(unix)]
fn test_id_single_invalid_user() {
    let args = &["hopefully_non_existing_username"];
    let result = new_ucmd!().args(args).run();
    let expected_result = expected_result(args);
    result
        .stdout_is(expected_result.stdout_str())
        .stderr_is(expected_result.stderr_str())
        .code_is(expected_result.code());
}

#[test]
#[cfg(unix)]
fn test_id_name() {
    let scene = TestScenario::new(util_name!());
    for &opt in &["--user", "--group", "--groups"] {
        let args = [opt, "--name"];
        let result = scene.ucmd().args(&args).run();
        let expected_result = expected_result(&args);
        result
            .stdout_is(expected_result.stdout_str())
            .stderr_is(expected_result.stderr_str())
            .code_is(expected_result.code());

        if opt == "--user" {
            assert_eq!(result.stdout_str().trim_end(), whoami());
        }
    }
}

#[test]
#[cfg(unix)]
fn test_id_real() {
    let scene = TestScenario::new(util_name!());
    for &opt in &["--user", "--group", "--groups"] {
        let args = [opt, "--real"];
        let result = scene.ucmd().args(&args).run();
        let expected_result = expected_result(&args);
        result
            .stdout_is(expected_result.stdout_str())
            .stderr_is(expected_result.stderr_str())
            .code_is(expected_result.code());
    }
}

#[test]
#[cfg(all(unix, not(target_os = "linux")))]
fn test_id_pretty_print() {
    // `-p` is BSD only and not supported on GNU's `id`
    let username = whoami();

    let result = new_ucmd!().arg("-p").run();
    if result.stdout_str().trim().is_empty() {
        // this fails only on: "MinRustV (ubuntu-latest, feat_os_unix)"
        // `rustc 1.40.0 (73528e339 2019-12-16)`
        // run: /home/runner/work/coreutils/coreutils/target/debug/coreutils id -p
        // thread 'test_id::test_id_pretty_print' panicked at 'Command was expected to succeed.
        // stdout =
        // stderr = ', tests/common/util.rs:157:13
        println!("test skipped:");
        return;
    } else {
        result.success().stdout_contains(username);
    }
}

#[test]
#[cfg(all(unix, not(target_os = "linux")))]
fn test_id_password_style() {
    // `-P` is BSD only and not supported on GNU's `id`
    let username = whoami();
    let result = new_ucmd!().arg("-P").arg(&username).succeeds();
    assert!(result.stdout_str().starts_with(&username));
}

#[test]
#[cfg(unix)]
fn test_id_default_format() {
    // TODO: These are the same tests like in test_id_zero but without --zero flag.
}

#[test]
#[cfg(unix)]
fn test_id_multiple_users() {
    // Same typical users that GNU testsuite is using.
    let test_users = ["root", "man", "postfix", "sshd", &whoami()];

    let result = new_ucmd!().args(&test_users).run();
    let expected_result = expected_result(&test_users);
    result
        .stdout_is(expected_result.stdout_str())
        .stderr_is(expected_result.stderr_str());
}

#[test]
#[cfg(unix)]
fn test_id_multiple_invalid_users() {
    let test_users = [
        "root",
        "hopefully_non_existing_username1",
        "man",
        "postfix",
        "sshd",
        "hopefully_non_existing_username2",
        &whoami(),
    ];

    let result = new_ucmd!().args(&test_users).run();
    let expected_result = expected_result(&test_users);
    result
        .stdout_is(expected_result.stdout_str())
        .stderr_is(expected_result.stderr_str());
}

#[test]
#[cfg(unix)]
fn test_id_zero() {
    let scene = TestScenario::new(util_name!());
    for z_flag in &["-z", "--zero"] {
        for &opt1 in &["--name", "--real"] {
            // id: cannot print only names or real IDs in default format
            let args = [opt1, z_flag];
            scene
                .ucmd()
                .args(&args)
                .fails()
                .stderr_only(expected_result(&args).stderr_str());
            for &opt2 in &["--user", "--group", "--groups"] {
                // u/g/G n/r z
                let args = [opt2, z_flag, opt1];
                let result = scene.ucmd().args(&args).run();
                let expected_result = expected_result(&args);
                result
                    .stdout_is(expected_result.stdout_str())
                    .stderr_is(expected_result.stderr_str());
            }
        }
        // u/g/G z
        for &opt2 in &["--user", "--group", "--groups"] {
            let args = [opt2, z_flag];
            scene
                .ucmd()
                .args(&args)
                .succeeds()
                .stdout_only(expected_result(&args).stdout_str());
        }
    }
}

#[allow(clippy::needless_borrow)]
#[cfg(unix)]
fn expected_result(args: &[&str]) -> CmdResult {
    #[cfg(target_os = "linux")]
    let util_name = util_name!();
    #[cfg(all(unix, not(target_os = "linux")))]
    let util_name = format!("g{}", util_name!());

    let result = TestScenario::new(&util_name)
        .cmd_keepenv(&util_name)
        .env("LANGUAGE", "C")
        .args(args)
        .run();

    let mut _o = 0;
    let mut _e = 0;
    #[cfg(all(unix, not(target_os = "linux")))]
    {
        _o = if result.stdout_str().starts_with(&util_name) {
            1
        } else {
            0
        };
        _e = if result.stderr_str().starts_with(&util_name) {
            1
        } else {
            0
        };
    }

    CmdResult::new(
        Some(result.tmpd()),
        Some(result.code()),
        result.succeeded(),
        &result.stdout()[_o..],
        &result.stderr()[_e..],
    )
}
<|endoftext|>


<commit_before>use cairo;

use librsvg::{
    CairoRenderer, DefsLookupErrorKind, HrefError, IntrinsicDimensions, Length, LengthUnit,
    RenderingError,
};

mod utils;

use self::utils::load_svg;

#[test]
fn no_intrinsic_dimensions() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"/>
"#,
    );

    assert_eq!(
        CairoRenderer::new(&svg).intrinsic_dimensions(),
        IntrinsicDimensions {
            width: None,
            height: None,
            vbox: None,
        }
    );
}

#[test]
fn has_intrinsic_dimensions() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="10cm" height="20" viewBox="0 0 100 200"/>
"#,
    );

    assert_eq!(
        CairoRenderer::new(&svg).intrinsic_dimensions(),
        IntrinsicDimensions {
            width: Some(Length::new(10.0, LengthUnit::Cm)),
            height: Some(Length::new(20.0, LengthUnit::Px)),
            vbox: Some(cairo::Rectangle {
                x: 0.0,
                y: 0.0,
                width: 100.0,
                height: 200.0,
            }),
        }
    );
}

#[test]
fn root_geometry_with_percent_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
  <rect x="10" y="20" width="30" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 0.0,
        y: 0.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer.geometry_for_layer(None, &viewport).unwrap();

    let rect = cairo::Rectangle {
        x: 10.0,
        y: 20.0,
        width: 30.0,
        height: 40.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_with_offset_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <rect x="10" y="20" width="30" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 100.0,
        y: 100.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer.geometry_for_layer(None, &viewport).unwrap();

    let rect = cairo::Rectangle {
        x: 110.0,
        y: 120.0,
        width: 30.0,
        height: 40.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_with_viewbox_and_offset_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="100 100 100 100">
  <rect x="110" y="120" width="30" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 100.0,
        y: 100.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer.geometry_for_layer(None, &viewport).unwrap();

    let rect = cairo::Rectangle {
        x: 110.0,
        y: 120.0,
        width: 30.0,
        height: 40.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_with_no_width_height() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="100 100 200 200">
  <rect x="110" y="120" width="30" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 100.0,
        y: 100.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer.geometry_for_layer(None, &viewport).unwrap();

    let rect = cairo::Rectangle {
        x: 105.0,
        y: 110.0,
        width: 15.0,
        height: 20.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_with_no_intrinsic_dimensions() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <rect x="110" y="120" width="50" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 100.0,
        y: 100.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer.geometry_for_layer(None, &viewport).unwrap();

    // The SVG document above has no width/height nor viewBox, which means it should
    // start with an identity transform for its coordinate space.  Since the viewport
    // is just offset by (100, 100), this just translates the coordinates of the <rect>.
    let rect = cairo::Rectangle {
        x: 210.0,
        y: 220.0,
        width: 50.0,
        height: 40.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_with_percent_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
  <rect id="foo" x="10" y="20" width="30" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 0.0,
        y: 0.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer
        .geometry_for_layer(Some("#foo"), &viewport)
        .unwrap();

    let rect = cairo::Rectangle {
        x: 10.0,
        y: 20.0,
        width: 30.0,
        height: 40.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_viewport_viewbox() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="400" viewBox="0 0 100 400">
  <rect id="one" x="0" y="0" width="100" height="200" fill="rgb(0,255,0)"/>
  <rect id="two" x="0" y="200" width="100" height="200" fill="rgb(0,0,255)"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 0.0,
        y: 0.0,
        width: 100.0,
        height: 400.0,
    };

    let (ink_r, logical_r) = renderer
        .geometry_for_layer(Some("#two"), &viewport)
        .unwrap();

    let rect = cairo::Rectangle {
        x: 0.0,
        y: 200.0,
        width: 100.0,
        height: 200.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_for_nonexistent_element() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"/>
"#,
    );

    let viewport = cairo::Rectangle {
        x: 0.0,
        y: 0.0,
        width: 100.0,
        height: 100.0,
    };

    let renderer = CairoRenderer::new(&svg);

    match renderer.geometry_for_layer(Some("#foo"), &viewport) {
        Err(RenderingError::InvalidId(DefsLookupErrorKind::NotFound)) => (),
        _ => panic!(),
    }
}

#[test]
fn layer_geometry_for_invalid_id() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"/>
"#,
    );

    let viewport = cairo::Rectangle {
        x: 0.0,
        y: 0.0,
        width: 100.0,
        height: 100.0,
    };

    let renderer = CairoRenderer::new(&svg);
    match renderer.geometry_for_layer(Some("foo"), &viewport) {
        Err(RenderingError::InvalidId(DefsLookupErrorKind::CannotLookupExternalReferences)) => (),
        _ => panic!(),
    }

    match renderer.geometry_for_layer(Some("foo.svg#foo"), &viewport) {
        Err(RenderingError::InvalidId(DefsLookupErrorKind::CannotLookupExternalReferences)) => (),
        _ => panic!(),
    }

    match renderer.geometry_for_layer(Some(""), &viewport) {
        Err(RenderingError::InvalidId(DefsLookupErrorKind::HrefError(HrefError::ParseError))) => (),
        _ => panic!(),
    }
}
<commit_msg>Add test with a percentage viewport<commit_after>use cairo;

use librsvg::{
    CairoRenderer, DefsLookupErrorKind, HrefError, IntrinsicDimensions, Length, LengthUnit,
    RenderingError,
};

mod utils;

use self::utils::load_svg;

#[test]
fn no_intrinsic_dimensions() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"/>
"#,
    );

    assert_eq!(
        CairoRenderer::new(&svg).intrinsic_dimensions(),
        IntrinsicDimensions {
            width: None,
            height: None,
            vbox: None,
        }
    );
}

#[test]
fn has_intrinsic_dimensions() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="10cm" height="20" viewBox="0 0 100 200"/>
"#,
    );

    assert_eq!(
        CairoRenderer::new(&svg).intrinsic_dimensions(),
        IntrinsicDimensions {
            width: Some(Length::new(10.0, LengthUnit::Cm)),
            height: Some(Length::new(20.0, LengthUnit::Px)),
            vbox: Some(cairo::Rectangle {
                x: 0.0,
                y: 0.0,
                width: 100.0,
                height: 200.0,
            }),
        }
    );
}

#[test]
fn root_geometry_with_percent_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
  <rect x="10" y="20" width="30" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 0.0,
        y: 0.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer.geometry_for_layer(None, &viewport).unwrap();

    let rect = cairo::Rectangle {
        x: 10.0,
        y: 20.0,
        width: 30.0,
        height: 40.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_with_offset_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <rect x="10" y="20" width="30" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 100.0,
        y: 100.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer.geometry_for_layer(None, &viewport).unwrap();

    let rect = cairo::Rectangle {
        x: 110.0,
        y: 120.0,
        width: 30.0,
        height: 40.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_with_viewbox_and_offset_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="100 100 100 100">
  <rect x="110" y="120" width="30" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 100.0,
        y: 100.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer.geometry_for_layer(None, &viewport).unwrap();

    let rect = cairo::Rectangle {
        x: 110.0,
        y: 120.0,
        width: 30.0,
        height: 40.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_with_no_width_height() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="100 100 200 200">
  <rect x="110" y="120" width="30" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 100.0,
        y: 100.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer.geometry_for_layer(None, &viewport).unwrap();

    let rect = cairo::Rectangle {
        x: 105.0,
        y: 110.0,
        width: 15.0,
        height: 20.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_with_no_intrinsic_dimensions() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <rect x="110" y="120" width="50" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 100.0,
        y: 100.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer.geometry_for_layer(None, &viewport).unwrap();

    // The SVG document above has no width/height nor viewBox, which means it should
    // start with an identity transform for its coordinate space.  Since the viewport
    // is just offset by (100, 100), this just translates the coordinates of the <rect>.
    let rect = cairo::Rectangle {
        x: 210.0,
        y: 220.0,
        width: 50.0,
        height: 40.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_with_percentage_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="50%">
  <rect x="10" y="20" width="50" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 100.0,
        y: 100.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer.geometry_for_layer(None, &viewport).unwrap();

    // Lack of viewBox means we use an identity transform, so the <rect> is just
    // offset by (100, 100) because of the viewport.
    let rect = cairo::Rectangle {
        x: 110.0,
        y: 120.0,
        width: 50.0,
        height: 40.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_with_percent_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
  <rect id="foo" x="10" y="20" width="30" height="40"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 0.0,
        y: 0.0,
        width: 100.0,
        height: 100.0,
    };

    let (ink_r, logical_r) = renderer
        .geometry_for_layer(Some("#foo"), &viewport)
        .unwrap();

    let rect = cairo::Rectangle {
        x: 10.0,
        y: 20.0,
        width: 30.0,
        height: 40.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_viewport_viewbox() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="400" viewBox="0 0 100 400">
  <rect id="one" x="0" y="0" width="100" height="200" fill="rgb(0,255,0)"/>
  <rect id="two" x="0" y="200" width="100" height="200" fill="rgb(0,0,255)"/>
</svg>
"#,
    );

    let renderer = CairoRenderer::new(&svg);

    let viewport = cairo::Rectangle {
        x: 0.0,
        y: 0.0,
        width: 100.0,
        height: 400.0,
    };

    let (ink_r, logical_r) = renderer
        .geometry_for_layer(Some("#two"), &viewport)
        .unwrap();

    let rect = cairo::Rectangle {
        x: 0.0,
        y: 200.0,
        width: 100.0,
        height: 200.0,
    };

    assert_eq!((ink_r, logical_r), (rect, rect));
}

#[test]
fn layer_geometry_for_nonexistent_element() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"/>
"#,
    );

    let viewport = cairo::Rectangle {
        x: 0.0,
        y: 0.0,
        width: 100.0,
        height: 100.0,
    };

    let renderer = CairoRenderer::new(&svg);

    match renderer.geometry_for_layer(Some("#foo"), &viewport) {
        Err(RenderingError::InvalidId(DefsLookupErrorKind::NotFound)) => (),
        _ => panic!(),
    }
}

#[test]
fn layer_geometry_for_invalid_id() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"/>
"#,
    );

    let viewport = cairo::Rectangle {
        x: 0.0,
        y: 0.0,
        width: 100.0,
        height: 100.0,
    };

    let renderer = CairoRenderer::new(&svg);
    match renderer.geometry_for_layer(Some("foo"), &viewport) {
        Err(RenderingError::InvalidId(DefsLookupErrorKind::CannotLookupExternalReferences)) => (),
        _ => panic!(),
    }

    match renderer.geometry_for_layer(Some("foo.svg#foo"), &viewport) {
        Err(RenderingError::InvalidId(DefsLookupErrorKind::CannotLookupExternalReferences)) => (),
        _ => panic!(),
    }

    match renderer.geometry_for_layer(Some(""), &viewport) {
        Err(RenderingError::InvalidId(DefsLookupErrorKind::HrefError(HrefError::ParseError))) => (),
        _ => panic!(),
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fs::File;
use std::io::{self, Read};

/// A simple prng based on a Linear congruential generator
/// https://en.wikipedia.org/wiki/Linear_congruential_generator
pub struct SimpleRng {
    seed: u64,
}

impl SimpleRng {
    /// Create a new SimpleRng
    pub fn new(seed: u64) -> SimpleRng {
        SimpleRng { seed }
    }

    /// Generate random u64
    pub fn rng(&mut self) -> u64 {
        // a simple Linear congruential generator
        let a: u64 = 6364136223846793005;
        let c: u64 = 1442695040888963407;
        self.seed = a.wrapping_mul(self.seed).wrapping_add(c);
        self.seed
    }
}

/// Samples `/dev/urandom` and generates a random ASCII string of length `len`
pub fn urandom_str(len: usize) -> io::Result<String> {
    const ASCII_CHARS: &'static [u8] = b"
          ABCDEFGHIJKLMNOPQRSTUVWXYZ\
          abcdefghijklmnopqrstuvwxyz\
          0123456789";

    File::open("/dev/urandom")?
        .bytes()
        .map(|b| b.map(|b| ASCII_CHARS[b as usize % ASCII_CHARS.len()] as char))
        .take(len)
        .collect::<io::Result<String>>()
}
<commit_msg>rand_ish: prevent spaces in urandom_str and use uniform samples only<commit_after>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fs::File;
use std::io::{self, Read};

/// A simple prng based on a Linear congruential generator
/// https://en.wikipedia.org/wiki/Linear_congruential_generator
pub struct SimpleRng {
    seed: u64,
}

impl SimpleRng {
    /// Create a new SimpleRng
    pub fn new(seed: u64) -> SimpleRng {
        SimpleRng { seed }
    }

    /// Generate random u64
    pub fn rng(&mut self) -> u64 {
        // a simple Linear congruential generator
        let a: u64 = 6364136223846793005;
        let c: u64 = 1442695040888963407;
        self.seed = a.wrapping_mul(self.seed).wrapping_add(c);
        self.seed
    }
}

// Uniformly samples the ASCII alphanumeric characters given a random variable. If an `Err` is
// passed in, the error is returned as `Some(Err(...))`. If the the random variable can not be used
// to uniformly sample, `None` is returned.
fn uniform_sample_ascii_alphanumeric(
    b: Result<u8, std::io::Error>,
) -> Option<Result<char, std::io::Error>> {
    const ASCII_CHARS: &'static [u8] = b"\
          ABCDEFGHIJKLMNOPQRSTUVWXYZ\
          abcdefghijklmnopqrstuvwxyz\
          0123456789";
    let char_index = match b {
        Ok(c) => c as usize,
        Err(e) => return Some(Err(e)),
    };
    // Throw away numbers that would cause sampling bias.
    if char_index >= ASCII_CHARS.len() * 4 {
        None
    } else {
        Some(Ok(ASCII_CHARS[char_index % ASCII_CHARS.len()] as char))
    }
}

/// Samples `/dev/urandom` and generates a random ASCII string of length `len`
pub fn urandom_str(len: usize) -> io::Result<String> {
    File::open("/dev/urandom")?
        .bytes()
        .filter_map(uniform_sample_ascii_alphanumeric)
        .take(len)
        .collect::<io::Result<String>>()
}

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

    #[test]
    fn check_100() {
        for i in 0..100 {
            let s = urandom_str(i).unwrap();
            assert_eq!(s.len(), i);
            assert!(s.is_ascii());
            assert!(!s.contains(' '));
            assert!(!s.contains(|c: char| !c.is_ascii_alphanumeric()));
        }
    }
}
<|endoftext|>


<commit_before>extern crate regex;
extern crate serde_json;

#[macro_use]
extern crate throw;

use throw::Result;

macro_rules! assert_matches {
    ($expected:expr, $actual:expr) => {{
        let expected = ($expected).replace("    ", "\t");
        let re = regex::Regex::new(&expected).expect("expected hardcoded regex to compile");

        let actual = format!("{}", $actual);

        assert!(
            re.is_match(&actual),
            format!(
                "expected error to match regex `\n{}\n`, but found `\n{}\n`",
                expected, actual
            )
        );
    }};
}

fn throw_static_message() -> Result<(), &'static str> {
    throw_new!("hi");
}

fn throw1() -> Result<(), ()> {
    throw_new!(());
}

fn throw2() -> Result<(), ()> {
    up!(throw1());
    Ok(())
}

fn throw3() -> Result<(), ()> {
    up!(throw2());
    Ok(())
}

fn throw_with_context1() -> Result<(), &'static str> {
    throw_new!("Error with context", "code"=>78,"application"=>"rust_core")
}

fn throw_with_context2() -> Result<(), &'static str> {
    up!(throw_with_context1(), "project_secret"=>"omega");
    Ok(())
}

fn throw_with_context3() -> Result<(), &'static str> {
    up!(throw_with_context2(),  "score"=>0.75, "height"=>948);
    Ok(())
}

fn gives_ok() -> Result<&'static str, &'static str> {
    Ok("ok")
}

fn throws_ok() -> Result<&'static str, &'static str> {
    let ok_msg = up!(gives_ok());
    Ok(ok_msg)
}

mod mod_test {
    use throw::Result;

    pub fn throws() -> Result<(), &'static str> {
        throw_new!("ahhhh");
    }
}

fn throws_into() -> Result<(), String> {
    throw!(Err("some static string"));
    Ok(())
}

fn throws_into_key_value() -> Result<(), String> {
    throw!(Err("some static string"), "key" => "value");
    Ok(())
}

fn throws_into_multiple_key_value_pairs() -> Result<(), String> {
    throw!(
        Err("some static string"),
        "key" => "value",
        "key2" => "value2",
        "key3" => "value3",
        "key4" => "value4",
    );
    Ok(())
}

#[test]
fn test_static_message() {
    let error = throw_static_message().unwrap_err();
    assert_eq!(*error.error(), "hi");
    assert_matches!(
        r#"Error: hi
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    );
    assert_eq!("hi".to_owned(), error.into_origin());
}

#[test]
#[cfg(any(feature = "serde-1", feature = "serde-1-std"))]
fn serialize_json() {
    let error = throw_with_context3().unwrap_err();
    let json = serde_json::to_string(&error).unwrap();
    assert_eq!(r#"{"points":[{"line":45,"column":4,"module_path":"exceptions_work","file":"tests/exceptions_work.rs"},{"line":49,"column":4,"module_path":"exceptions_work","file":"tests/exceptions_work.rs"},{"line":54,"column":4,"module_path":"exceptions_work","file":"tests/exceptions_work.rs"}],"context":[{"key":"code","value":78},{"key":"application","value":"rust_core"},{"key":"project_secret","value":"omega"},{"key":"score","value":0.75},{"key":"height","value":948}],"error":"Error with context"}"#, json);
}

#[test]
fn test_throw_with_context() {
    let error = throw_with_context1().unwrap_err();
    assert_eq!(error.get_context().len(), 2);

    let error2 = throw_with_context3().unwrap_err();
    assert_eq!(error2.get_context().len(), 5);

    assert_matches!(
        r#"Error: "Error with context"
    height: 948
	score: 0.75
	project_secret: omega
	application: rust_core
	code: 78
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        format!("{:?}", error2)
    );
}

#[test]
#[allow(deprecated)]
fn test_multiple_throws() {
    let error = throw3().unwrap_err();
    assert_eq!(error.error(), &());
    assert_eq!(error.error(), error.original_error());
    assert_matches!(
        r#"Error: \(\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        format!("{:?}", error)
    );
}

#[test]
fn test_returns_ok() {
    let ok = throws_ok().unwrap();
    assert_eq!(ok, "ok");
}

#[test]
fn test_mod_throw() {
    let error = mod_test::throws().unwrap_err();
    assert_matches!(
        r#"Error: ahhhh
    at [0-9]+:[0-9] in exceptions_work::mod_test \([a-z/._-]+\)"#,
        error
    );
}

#[test]
fn test_throws_into() {
    let error = throws_into().unwrap_err();
    assert_matches!(
        r#"Error: some static string
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    )
}

#[test]
fn test_throws_into_key_value() {
    let error = throws_into_key_value().unwrap_err();
    assert_matches!(
        r#"Error: some static string
    key: value
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    )
}

#[test]
fn test_throws_into_multiple_key_value_pairs() {
    let error = throws_into_multiple_key_value_pairs().unwrap_err();
    assert_matches!(
        r#"Error: some static string
    key4: value4
    key3: value3
    key2: value2
    key: value
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    )
}
<commit_msg>Make serialize test more robust so it does not rely on line numbers.<commit_after>extern crate regex;
extern crate serde_json;

#[macro_use]
extern crate throw;

use throw::Result;

macro_rules! assert_matches {
    ($expected:expr, $actual:expr) => {{
        let expected = ($expected).replace("    ", "\t");
        let re = regex::Regex::new(&expected).expect("expected hardcoded regex to compile");

        let actual = format!("{}", $actual);

        assert!(
            re.is_match(&actual),
            format!(
                "expected error to match regex `\n{}\n`, but found `\n{}\n`",
                expected, actual
            )
        );
    }};
}

fn throw_static_message() -> Result<(), &'static str> {
    throw_new!("hi");
}

fn throw1() -> Result<(), ()> {
    throw_new!(());
}

fn throw2() -> Result<(), ()> {
    up!(throw1());
    Ok(())
}

fn throw3() -> Result<(), ()> {
    up!(throw2());
    Ok(())
}

fn throw_with_context1() -> Result<(), &'static str> {
    throw_new!("Error with context", "code"=>78,"application"=>"rust_core")
}

fn throw_with_context2() -> Result<(), &'static str> {
    up!(throw_with_context1(), "project_secret"=>"omega");
    Ok(())
}

fn throw_with_context3() -> Result<(), &'static str> {
    up!(throw_with_context2(),  "score"=>0.75, "height"=>948);
    Ok(())
}

fn gives_ok() -> Result<&'static str, &'static str> {
    Ok("ok")
}

fn throws_ok() -> Result<&'static str, &'static str> {
    let ok_msg = up!(gives_ok());
    Ok(ok_msg)
}

mod mod_test {
    use throw::Result;

    pub fn throws() -> Result<(), &'static str> {
        throw_new!("ahhhh");
    }
}

fn throws_into() -> Result<(), String> {
    throw!(Err("some static string"));
    Ok(())
}

fn throws_into_key_value() -> Result<(), String> {
    throw!(Err("some static string"), "key" => "value");
    Ok(())
}

fn throws_into_multiple_key_value_pairs() -> Result<(), String> {
    throw!(
        Err("some static string"),
        "key" => "value",
        "key2" => "value2",
        "key3" => "value3",
        "key4" => "value4",
    );
    Ok(())
}

#[test]
fn test_static_message() {
    let error = throw_static_message().unwrap_err();
    assert_eq!(*error.error(), "hi");
    assert_matches!(
        r#"Error: hi
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    );
    assert_eq!("hi".to_owned(), error.into_origin());
}

#[test]
#[cfg(any(feature = "serde-1", feature = "serde-1-std"))]
fn serialize_json() {
    let error = throw_with_context3().unwrap_err();
    let json = serde_json::to_string(&error).unwrap();
    let whitespace_trim = regex::Regex::new("\\s+").unwrap();
    let expected = r#"\{
        "points":\[
            \{"line":[0-9]+,"column":[0-9]+,"module_path":"exceptions_work",
                "file":"tests/exceptions_work.rs"\},
            \{"line":[0-9]+,"column":[0-9]+,"module_path":"exceptions_work",
                "file":"tests/exceptions_work.rs"\},
            \{"line":[0-9]+,"column":[0-9]+,"module_path":"exceptions_work",
                "file":"tests/exceptions_work.rs"\}
        \],
        "context":\[
            \{"key":"code","value":78\},
            \{"key":"application","value":"rust_core"\},
            \{"key":"project_secret","value":"omega"\},
            \{"key":"score","value":0.75\},
            \{"key":"height","value":948\}
        \],
        "error":"Error with context"
    \}"#;
    assert_matches!(whitespace_trim.replace_all(expected, "\\s*"), json);
}

#[test]
fn test_throw_with_context() {
    let error = throw_with_context1().unwrap_err();
    assert_eq!(error.get_context().len(), 2);

    let error2 = throw_with_context3().unwrap_err();
    assert_eq!(error2.get_context().len(), 5);

    assert_matches!(
        r#"Error: "Error with context"
    height: 948
	score: 0.75
	project_secret: omega
	application: rust_core
	code: 78
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        format!("{:?}", error2)
    );
}

#[test]
#[allow(deprecated)]
fn test_multiple_throws() {
    let error = throw3().unwrap_err();
    assert_eq!(error.error(), &());
    assert_eq!(error.error(), error.original_error());
    assert_matches!(
        r#"Error: \(\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        format!("{:?}", error)
    );
}

#[test]
fn test_returns_ok() {
    let ok = throws_ok().unwrap();
    assert_eq!(ok, "ok");
}

#[test]
fn test_mod_throw() {
    let error = mod_test::throws().unwrap_err();
    assert_matches!(
        r#"Error: ahhhh
    at [0-9]+:[0-9] in exceptions_work::mod_test \([a-z/._-]+\)"#,
        error
    );
}

#[test]
fn test_throws_into() {
    let error = throws_into().unwrap_err();
    assert_matches!(
        r#"Error: some static string
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    )
}

#[test]
fn test_throws_into_key_value() {
    let error = throws_into_key_value().unwrap_err();
    assert_matches!(
        r#"Error: some static string
    key: value
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    )
}

#[test]
fn test_throws_into_multiple_key_value_pairs() {
    let error = throws_into_multiple_key_value_pairs().unwrap_err();
    assert_matches!(
        r#"Error: some static string
    key4: value4
    key3: value3
    key2: value2
    key: value
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    )
}
<|endoftext|>


<commit_before>use objects::User;
use objects::Chat;
use objects::MessageEntity;

/// Represents a Telegram message.
#[derive(Clone, Deserialize, Debug)]
pub struct Message {
    pub message_id: i64,
    pub from: Option<User>,
    pub date: i64,
    pub chat: Chat,
    pub forward_from: Option<User>,
    pub forward_from_chat: Option<Chat>,
    pub forward_from_message_id: Option<i64>,
    pub forward_date: Option<i64>,
    pub reply_to_message: Option<Box<Message>>,
    pub edit_date: Option<i64>,
    pub text: Option<String>,
    pub entities: Option<Vec<MessageEntity>>,
    pub audio: Option<String>,
    pub document: Option<String>,
    pub game: Option<String>,
    pub photo: Option<String>,
    pub sticker: Option<String>,
    pub video: Option<String>,
    pub voice: Option<String>,
    pub caption: Option<String>,
    pub contact: Option<String>,
    pub location: Option<String>,
    pub venue: Option<String>,
    pub new_chat_member: Option<User>,
    pub left_chat_member: Option<User>,
    pub new_chat_title: Option<String>,
    pub new_chat_photo: Option<String>,
    pub delete_chat_photo: Option<bool>,
    pub group_chat_created: Option<bool>,
    pub supergroup_chat_created: Option<bool>,
    pub channel_chat_created: Option<bool>,
    pub migrate_to_chat_id: Option<i64>,
    pub migrate_from_chat_id: Option<i64>,
    pub pinned_message: Option<Box<Message>>,
}
<commit_msg>changed pub contact: Option<String> to Option<Contact><commit_after>use objects::User;
use objects::Chat;
use objects::MessageEntity;
use objects::Contact;

/// Represents a Telegram message.
#[derive(Clone, Deserialize, Debug)]
pub struct Message {
    pub message_id: i64,
    pub from: Option<User>,
    pub date: i64,
    pub chat: Chat,
    pub forward_from: Option<User>,
    pub forward_from_chat: Option<Chat>,
    pub forward_from_message_id: Option<i64>,
    pub forward_date: Option<i64>,
    pub reply_to_message: Option<Box<Message>>,
    pub edit_date: Option<i64>,
    pub text: Option<String>,
    pub entities: Option<Vec<MessageEntity>>,
    pub audio: Option<String>,
    pub document: Option<String>,
    pub game: Option<String>,
    pub photo: Option<String>,
    pub sticker: Option<String>,
    pub video: Option<String>,
    pub voice: Option<String>,
    pub caption: Option<String>,
    pub contact: Option<Contact>,
    pub location: Option<String>,
    pub venue: Option<String>,
    pub new_chat_member: Option<User>,
    pub left_chat_member: Option<User>,
    pub new_chat_title: Option<String>,
    pub new_chat_photo: Option<String>,
    pub delete_chat_photo: Option<bool>,
    pub group_chat_created: Option<bool>,
    pub supergroup_chat_created: Option<bool>,
    pub channel_chat_created: Option<bool>,
    pub migrate_to_chat_id: Option<i64>,
    pub migrate_from_chat_id: Option<i64>,
    pub pinned_message: Option<Box<Message>>,
}
<|endoftext|>


<commit_before>//! Geometric traits.
//!
//! This module provides traits that specify the geometry of `MeshGraph`s and
//! express the spatial operations supported by that geometry. The most basic
//! and only required trait is `GraphGeometry`, which uses associated types to
//! specify the type of the `geometry` field in the payloads for vertices,
//! arcs, edges, and faces in a graph.
//!
//! To support useful spatial operations, types that implement `GraphGeometry`
//! may also implement `AsPosition`. The `AsPosition` trait exposes positional
//! data in vertices. If that positional data also implements spatial traits
//! from the [`theon`](https://crates.io/crates/theon) crate, then spatial
//! operations will be enabled, such as `smooth`, `split_at_midpoint`, and
//! `poke_with_offset`.
//!
//! This module also defines traits that define the capabilities of geometry in
//! a `MeshGraph`. These traits enable generic code without the need to express
//! complicated relationships between types representing a Euclidean space. For
//! example, the `FaceCentroid` trait is defined for `GraphGeometry` types that
//! expose positional data that implements the necessary traits to compute the
//! centroid of a face.
//!
//! # Examples
//!
//! A function that subdivides faces in a graph by splitting edges at their
//! midpoints:
//!
//! ```rust
//! # extern crate plexus;
//! # extern crate smallvec;
//! #
//! use plexus::graph::{EdgeMidpoint, FaceView, GraphGeometry, MeshGraph};
//! use plexus::prelude::*;
//! use plexus::AsPosition;
//! use smallvec::SmallVec;
//!
//! # fn main() {
//! // Requires `EdgeMidpoint` for `split_at_midpoint`.
//! pub fn circumscribe<G>(face: FaceView<&mut MeshGraph<G>, G>) -> FaceView<&mut MeshGraph<G>, G>
//! where
//!     G: EdgeMidpoint + GraphGeometry,
//!     G::Vertex: AsPosition,
//! {
//!     let arity = face.arity();
//!     let mut arc = face.into_arc();
//!     let mut splits = SmallVec::<[_; 4]>::with_capacity(arity);
//!     for _ in 0..arity {
//!         let vertex = arc.split_at_midpoint();
//!         splits.push(vertex.key());
//!         arc = vertex.into_outgoing_arc().into_next_arc();
//!     }
//!     let mut face = arc.into_face().unwrap();
//!     for (a, b) in splits.into_iter().perimeter() {
//!         face = face.split(ByKey(a), ByKey(b)).unwrap().into_face().unwrap();
//!     }
//!     face
//! }
//! # }
//! ```

// TODO: Integrate this module documentation into the `graph` module.

// Geometric traits like `FaceNormal` and `EdgeMidpoint` are defined in such a
// way to reduce the contraints necessary for writing generic user code. With
// few exceptions, these traits only depend on `AsPosition` being implemented
// by the `Vertex` type in their definition. If a more complex implementation
// is necessary, constraints are specified there so that they do not pollute
// user code.

use theon::ops::{Cross, Interpolate, Project};
use theon::query::Plane;
use theon::space::{EuclideanSpace, FiniteDimensional, InnerSpace, Vector, VectorSpace};
use theon::{AsPosition, FromItems, Position};
use typenum::U3;

use crate::graph::borrow::Reborrow;
use crate::graph::mutation::Consistent;
use crate::graph::storage::payload::{ArcPayload, EdgePayload, FacePayload, VertexPayload};
use crate::graph::storage::AsStorage;
use crate::graph::view::edge::{ArcView, CompositeEdge};
use crate::graph::view::face::Ring;
use crate::graph::view::vertex::VertexView;
use crate::graph::{GraphError, OptionExt as _};

pub type VertexPosition<G> = Position<<G as GraphGeometry>::Vertex>;

// TODO: Require `Clone` instead of `Copy` once non-`Copy` types are supported
//       by the slotmap crate. See https://github.com/orlp/slotmap/issues/27
/// Graph geometry.
///
/// Specifies the types used to represent geometry for vertices, arcs, edges,
/// and faces in a graph. Arbitrary types can be used, including `()` for no
/// geometry at all.
///
/// Geometry is vertex-based. Geometric operations depend on understanding the
/// positional data in vertices exposed by the `AsPosition` trait.
///
/// # Examples
///
/// ```rust
/// # extern crate decorum;
/// # extern crate nalgebra;
/// # extern crate num;
/// # extern crate plexus;
/// #
/// use decorum::N64;
/// use nalgebra::{Point3, Vector4};
/// use num::Zero;
/// use plexus::graph::{GraphGeometry, MeshGraph};
/// use plexus::prelude::*;
/// use plexus::primitive::generate::Position;
/// use plexus::primitive::sphere::UvSphere;
/// use plexus::{AsPosition, IntoGeometry};
///
/// // Vertex-only geometry with position and color data.
/// #[derive(Clone, Copy, Eq, Hash, PartialEq)]
/// pub struct Vertex {
///     pub position: Point3<N64>,
///     pub color: Vector4<N64>,
/// }
///
/// impl GraphGeometry for Vertex {
///     type Vertex = Self;
///     type Arc = ();
///     type Edge = ();
///     type Face = ();
/// }
///
/// impl AsPosition for Vertex {
///     type Position = Point3<N64>;
///
///     fn as_position(&self) -> &Self::Position {
///         &self.position
///     }
///
///     fn as_position_mut(&mut self) -> &mut Self::Position {
///         &mut self.position
///     }
/// }
///
/// # fn main() {
/// // Create a mesh from a sphere primitive and map the geometry data.
/// let mut graph = UvSphere::new(8, 8)
///     .polygons::<Position<Point3<N64>>>()
///     .map_vertices(|position| Vertex {
///         position,
///         color: Zero::zero(),
///     })
///     .collect::<MeshGraph<Vertex>>();
/// # }
/// ```
pub trait GraphGeometry: Sized {
    type Vertex: Copy;
    type Arc: Copy + Default;
    type Edge: Copy + Default;
    type Face: Copy + Default;
}

impl GraphGeometry for () {
    type Vertex = ();
    type Arc = ();
    type Edge = ();
    type Face = ();
}

impl<T> GraphGeometry for (T, T)
where
    T: Copy,
{
    type Vertex = Self;
    type Arc = ();
    type Edge = ();
    type Face = ();
}

impl<T> GraphGeometry for (T, T, T)
where
    T: Copy,
{
    type Vertex = Self;
    type Arc = ();
    type Edge = ();
    type Face = ();
}

impl<T> GraphGeometry for [T; 2]
where
    T: Copy,
{
    type Vertex = Self;
    type Arc = ();
    type Edge = ();
    type Face = ();
}

impl<T> GraphGeometry for [T; 3]
where
    T: Copy,
{
    type Vertex = Self;
    type Arc = ();
    type Edge = ();
    type Face = ();
}

pub trait VertexCentroid: GraphGeometry
where
    Self::Vertex: AsPosition,
{
    fn centroid<M>(vertex: VertexView<M, Self>) -> Result<VertexPosition<Self>, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent,
    {
        VertexPosition::<Self>::centroid(
            vertex
                .neighboring_vertices()
                .map(|vertex| *vertex.geometry.as_position()),
        )
        .ok_or_else(|| GraphError::TopologyNotFound)
    }
}

impl<G> VertexCentroid for G
where
    G: GraphGeometry,
    G::Vertex: AsPosition,
{
}

pub trait VertexNormal: FaceNormal
where
    Self::Vertex: AsPosition,
{
    fn normal<M>(vertex: VertexView<M, Self>) -> Result<Vector<VertexPosition<Self>>, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>>
            + AsStorage<FacePayload<Self>>
            + AsStorage<VertexPayload<Self>>
            + Consistent,
    {
        Vector::<VertexPosition<Self>>::mean(
            vertex
                .neighboring_faces()
                .map(<Self as FaceNormal>::normal)
                .collect::<Result<Vec<_>, _>>()?,
        )
        .ok_or_else(|| GraphError::TopologyNotFound)?
        .normalize()
        .ok_or_else(|| GraphError::Geometry)
    }
}

impl<G> VertexNormal for G
where
    G: FaceNormal,
    G::Vertex: AsPosition,
{
}

pub trait ArcNormal: GraphGeometry
where
    Self::Vertex: AsPosition,
{
    fn normal<M>(arc: ArcView<M, Self>) -> Result<Vector<VertexPosition<Self>>, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent;
}

impl<G> ArcNormal for G
where
    G: GraphGeometry,
    G::Vertex: AsPosition,
    VertexPosition<G>: EuclideanSpace,
    Vector<VertexPosition<G>>: Project<Output = Vector<VertexPosition<G>>>,
{
    fn normal<M>(arc: ArcView<M, Self>) -> Result<Vector<VertexPosition<Self>>, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent,
    {
        let (a, b) = FromItems::from_items(arc.vertices().map(|vertex| *vertex.position()))
            .expect_consistent();
        let c = *arc.next_arc().destination_vertex().position();
        let ab = a - b;
        let cb = c - b;
        let p = b + ab.project(cb);
        (p - c).normalize().ok_or_else(|| GraphError::Geometry)
    }
}

pub trait EdgeMidpoint: GraphGeometry
where
    Self::Vertex: AsPosition,
{
    fn midpoint<E, M>(edge: E) -> Result<VertexPosition<Self>, GraphError>
    where
        E: CompositeEdge<M, Self>,
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>>
            + AsStorage<EdgePayload<Self>>
            + AsStorage<VertexPayload<Self>>
            + Consistent;
}

impl<G> EdgeMidpoint for G
where
    G: GraphGeometry,
    G::Vertex: AsPosition,
    VertexPosition<G>: Interpolate<Output = VertexPosition<G>>,
{
    fn midpoint<E, M>(edge: E) -> Result<VertexPosition<Self>, GraphError>
    where
        E: CompositeEdge<M, Self>,
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>>
            + AsStorage<EdgePayload<Self>>
            + AsStorage<VertexPayload<Self>>
            + Consistent,
    {
        let arc = edge.into_arc();
        let (a, b) =
            FromItems::from_items(arc.vertices().map(|vertex| *vertex.position())).unwrap();
        Ok(a.midpoint(b))
    }
}

pub trait FaceCentroid: GraphGeometry
where
    Self::Vertex: AsPosition,
{
    fn centroid<R, M>(ring: R) -> Result<VertexPosition<Self>, GraphError>
    where
        R: Ring<M, Self>,
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent,
    {
        Ok(
            VertexPosition::<Self>::centroid(ring.vertices().map(|vertex| *vertex.position()))
                .expect_consistent(),
        )
    }
}

impl<G> FaceCentroid for G
where
    G: GraphGeometry,
    G::Vertex: AsPosition,
{
}

pub trait FaceNormal: GraphGeometry
where
    Self::Vertex: AsPosition,
{
    fn normal<R, M>(ring: R) -> Result<Vector<VertexPosition<Self>>, GraphError>
    where
        R: Ring<M, Self>,
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent;
}

impl<G> FaceNormal for G
where
    G: FaceCentroid + GraphGeometry,
    G::Vertex: AsPosition,
    Vector<VertexPosition<G>>: Cross<Output = Vector<VertexPosition<G>>>,
    VertexPosition<G>: EuclideanSpace,
{
    fn normal<R, M>(ring: R) -> Result<Vector<VertexPosition<Self>>, GraphError>
    where
        R: Ring<M, Self>,
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent,
    {
        let (a, b) =
            FromItems::from_items(ring.vertices().take(2).map(|vertex| *vertex.position()))
                .expect_consistent();
        let c = G::centroid(ring)?;
        let ab = a - b;
        let bc = b - c;
        ab.cross(bc).normalize().ok_or_else(|| GraphError::Geometry)
    }
}

pub trait FacePlane: GraphGeometry
where
    Self::Vertex: AsPosition,
    VertexPosition<Self>: FiniteDimensional<N = U3>,
{
    fn plane<R, M>(ring: R) -> Result<Plane<VertexPosition<Self>>, GraphError>
    where
        R: Ring<M, Self>,
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent;
}

// TODO: The `array` feature only supports Linux. See
//       https://github.com/olson-sean-k/theon/issues/1
#[cfg(target_os = "linux")]
mod array {
    use super::*;

    use smallvec::SmallVec;
    use theon::array::ArrayScalar;
    use theon::space::Scalar;
    use theon::{FromItems, IntoItems};

    impl<G> FacePlane for G
    where
        G: GraphGeometry,
        G::Vertex: AsPosition,
        VertexPosition<G>: EuclideanSpace + FiniteDimensional<N = U3>,
        Scalar<VertexPosition<G>>: ArrayScalar,
        Vector<VertexPosition<G>>: FromItems + IntoItems,
    {
        fn plane<R, M>(ring: R) -> Result<Plane<VertexPosition<G>>, GraphError>
        where
            R: Ring<M, Self>,
            M: Reborrow,
            M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent,
        {
            let points = ring
                .vertices()
                .map(|vertex| *vertex.geometry.as_position())
                .collect::<SmallVec<[_; 4]>>();
            Plane::from_points(points).ok_or_else(|| GraphError::Geometry)
        }
    }
}
<commit_msg>Do not emit topology errors in geometry traits.<commit_after>//! Geometric traits.
//!
//! This module provides traits that specify the geometry of `MeshGraph`s and
//! express the spatial operations supported by that geometry. The most basic
//! and only required trait is `GraphGeometry`, which uses associated types to
//! specify the type of the `geometry` field in the payloads for vertices,
//! arcs, edges, and faces in a graph.
//!
//! To support useful spatial operations, types that implement `GraphGeometry`
//! may also implement `AsPosition`. The `AsPosition` trait exposes positional
//! data in vertices. If that positional data also implements spatial traits
//! from the [`theon`](https://crates.io/crates/theon) crate, then spatial
//! operations will be enabled, such as `smooth`, `split_at_midpoint`, and
//! `poke_with_offset`.
//!
//! This module also defines traits that define the capabilities of geometry in
//! a `MeshGraph`. These traits enable generic code without the need to express
//! complicated relationships between types representing a Euclidean space. For
//! example, the `FaceCentroid` trait is defined for `GraphGeometry` types that
//! expose positional data that implements the necessary traits to compute the
//! centroid of a face.
//!
//! # Examples
//!
//! A function that subdivides faces in a graph by splitting edges at their
//! midpoints:
//!
//! ```rust
//! # extern crate plexus;
//! # extern crate smallvec;
//! #
//! use plexus::graph::{EdgeMidpoint, FaceView, GraphGeometry, MeshGraph};
//! use plexus::prelude::*;
//! use plexus::AsPosition;
//! use smallvec::SmallVec;
//!
//! # fn main() {
//! // Requires `EdgeMidpoint` for `split_at_midpoint`.
//! pub fn circumscribe<G>(face: FaceView<&mut MeshGraph<G>, G>) -> FaceView<&mut MeshGraph<G>, G>
//! where
//!     G: EdgeMidpoint + GraphGeometry,
//!     G::Vertex: AsPosition,
//! {
//!     let arity = face.arity();
//!     let mut arc = face.into_arc();
//!     let mut splits = SmallVec::<[_; 4]>::with_capacity(arity);
//!     for _ in 0..arity {
//!         let vertex = arc.split_at_midpoint();
//!         splits.push(vertex.key());
//!         arc = vertex.into_outgoing_arc().into_next_arc();
//!     }
//!     let mut face = arc.into_face().unwrap();
//!     for (a, b) in splits.into_iter().perimeter() {
//!         face = face.split(ByKey(a), ByKey(b)).unwrap().into_face().unwrap();
//!     }
//!     face
//! }
//! # }
//! ```

// TODO: Integrate this module documentation into the `graph` module.

// Geometric traits like `FaceNormal` and `EdgeMidpoint` are defined in such a
// way to reduce the contraints necessary for writing generic user code. With
// few exceptions, these traits only depend on `AsPosition` being implemented
// by the `Vertex` type in their definition. If a more complex implementation
// is necessary, constraints are specified there so that they do not pollute
// user code.

use theon::ops::{Cross, Interpolate, Project};
use theon::query::Plane;
use theon::space::{EuclideanSpace, FiniteDimensional, InnerSpace, Vector, VectorSpace};
use theon::{AsPosition, FromItems, Position};
use typenum::U3;

use crate::graph::borrow::Reborrow;
use crate::graph::mutation::Consistent;
use crate::graph::storage::payload::{ArcPayload, EdgePayload, FacePayload, VertexPayload};
use crate::graph::storage::AsStorage;
use crate::graph::view::edge::{ArcView, CompositeEdge};
use crate::graph::view::face::Ring;
use crate::graph::view::vertex::VertexView;
use crate::graph::{GraphError, OptionExt as _};

pub type VertexPosition<G> = Position<<G as GraphGeometry>::Vertex>;

// TODO: Require `Clone` instead of `Copy` once non-`Copy` types are supported
//       by the slotmap crate. See https://github.com/orlp/slotmap/issues/27
/// Graph geometry.
///
/// Specifies the types used to represent geometry for vertices, arcs, edges,
/// and faces in a graph. Arbitrary types can be used, including `()` for no
/// geometry at all.
///
/// Geometry is vertex-based. Geometric operations depend on understanding the
/// positional data in vertices exposed by the `AsPosition` trait.
///
/// # Examples
///
/// ```rust
/// # extern crate decorum;
/// # extern crate nalgebra;
/// # extern crate num;
/// # extern crate plexus;
/// #
/// use decorum::N64;
/// use nalgebra::{Point3, Vector4};
/// use num::Zero;
/// use plexus::graph::{GraphGeometry, MeshGraph};
/// use plexus::prelude::*;
/// use plexus::primitive::generate::Position;
/// use plexus::primitive::sphere::UvSphere;
/// use plexus::{AsPosition, IntoGeometry};
///
/// // Vertex-only geometry with position and color data.
/// #[derive(Clone, Copy, Eq, Hash, PartialEq)]
/// pub struct Vertex {
///     pub position: Point3<N64>,
///     pub color: Vector4<N64>,
/// }
///
/// impl GraphGeometry for Vertex {
///     type Vertex = Self;
///     type Arc = ();
///     type Edge = ();
///     type Face = ();
/// }
///
/// impl AsPosition for Vertex {
///     type Position = Point3<N64>;
///
///     fn as_position(&self) -> &Self::Position {
///         &self.position
///     }
///
///     fn as_position_mut(&mut self) -> &mut Self::Position {
///         &mut self.position
///     }
/// }
///
/// # fn main() {
/// // Create a mesh from a sphere primitive and map the geometry data.
/// let mut graph = UvSphere::new(8, 8)
///     .polygons::<Position<Point3<N64>>>()
///     .map_vertices(|position| Vertex {
///         position,
///         color: Zero::zero(),
///     })
///     .collect::<MeshGraph<Vertex>>();
/// # }
/// ```
pub trait GraphGeometry: Sized {
    type Vertex: Copy;
    type Arc: Copy + Default;
    type Edge: Copy + Default;
    type Face: Copy + Default;
}

impl GraphGeometry for () {
    type Vertex = ();
    type Arc = ();
    type Edge = ();
    type Face = ();
}

impl<T> GraphGeometry for (T, T)
where
    T: Copy,
{
    type Vertex = Self;
    type Arc = ();
    type Edge = ();
    type Face = ();
}

impl<T> GraphGeometry for (T, T, T)
where
    T: Copy,
{
    type Vertex = Self;
    type Arc = ();
    type Edge = ();
    type Face = ();
}

impl<T> GraphGeometry for [T; 2]
where
    T: Copy,
{
    type Vertex = Self;
    type Arc = ();
    type Edge = ();
    type Face = ();
}

impl<T> GraphGeometry for [T; 3]
where
    T: Copy,
{
    type Vertex = Self;
    type Arc = ();
    type Edge = ();
    type Face = ();
}

pub trait VertexCentroid: GraphGeometry
where
    Self::Vertex: AsPosition,
{
    fn centroid<M>(vertex: VertexView<M, Self>) -> Result<VertexPosition<Self>, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent,
    {
        Ok(VertexPosition::<Self>::centroid(
            vertex
                .neighboring_vertices()
                .map(|vertex| *vertex.geometry.as_position()),
        )
        .expect_consistent())
    }
}

impl<G> VertexCentroid for G
where
    G: GraphGeometry,
    G::Vertex: AsPosition,
{
}

pub trait VertexNormal: FaceNormal
where
    Self::Vertex: AsPosition,
{
    fn normal<M>(vertex: VertexView<M, Self>) -> Result<Vector<VertexPosition<Self>>, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>>
            + AsStorage<FacePayload<Self>>
            + AsStorage<VertexPayload<Self>>
            + Consistent,
    {
        Vector::<VertexPosition<Self>>::mean(
            vertex
                .neighboring_faces()
                .map(<Self as FaceNormal>::normal)
                .collect::<Result<Vec<_>, _>>()?,
        )
        .expect_consistent()
        .normalize()
        .ok_or_else(|| GraphError::Geometry)
    }
}

impl<G> VertexNormal for G
where
    G: FaceNormal,
    G::Vertex: AsPosition,
{
}

pub trait ArcNormal: GraphGeometry
where
    Self::Vertex: AsPosition,
{
    fn normal<M>(arc: ArcView<M, Self>) -> Result<Vector<VertexPosition<Self>>, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent;
}

impl<G> ArcNormal for G
where
    G: GraphGeometry,
    G::Vertex: AsPosition,
    VertexPosition<G>: EuclideanSpace,
    Vector<VertexPosition<G>>: Project<Output = Vector<VertexPosition<G>>>,
{
    fn normal<M>(arc: ArcView<M, Self>) -> Result<Vector<VertexPosition<Self>>, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent,
    {
        let (a, b) = FromItems::from_items(arc.vertices().map(|vertex| *vertex.position()))
            .expect_consistent();
        let c = *arc.next_arc().destination_vertex().position();
        let ab = a - b;
        let cb = c - b;
        let p = b + ab.project(cb);
        (p - c).normalize().ok_or_else(|| GraphError::Geometry)
    }
}

pub trait EdgeMidpoint: GraphGeometry
where
    Self::Vertex: AsPosition,
{
    fn midpoint<E, M>(edge: E) -> Result<VertexPosition<Self>, GraphError>
    where
        E: CompositeEdge<M, Self>,
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>>
            + AsStorage<EdgePayload<Self>>
            + AsStorage<VertexPayload<Self>>
            + Consistent;
}

impl<G> EdgeMidpoint for G
where
    G: GraphGeometry,
    G::Vertex: AsPosition,
    VertexPosition<G>: Interpolate<Output = VertexPosition<G>>,
{
    fn midpoint<E, M>(edge: E) -> Result<VertexPosition<Self>, GraphError>
    where
        E: CompositeEdge<M, Self>,
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>>
            + AsStorage<EdgePayload<Self>>
            + AsStorage<VertexPayload<Self>>
            + Consistent,
    {
        let arc = edge.into_arc();
        let (a, b) =
            FromItems::from_items(arc.vertices().map(|vertex| *vertex.position())).unwrap();
        Ok(a.midpoint(b))
    }
}

pub trait FaceCentroid: GraphGeometry
where
    Self::Vertex: AsPosition,
{
    fn centroid<R, M>(ring: R) -> Result<VertexPosition<Self>, GraphError>
    where
        R: Ring<M, Self>,
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent,
    {
        Ok(
            VertexPosition::<Self>::centroid(ring.vertices().map(|vertex| *vertex.position()))
                .expect_consistent(),
        )
    }
}

impl<G> FaceCentroid for G
where
    G: GraphGeometry,
    G::Vertex: AsPosition,
{
}

pub trait FaceNormal: GraphGeometry
where
    Self::Vertex: AsPosition,
{
    fn normal<R, M>(ring: R) -> Result<Vector<VertexPosition<Self>>, GraphError>
    where
        R: Ring<M, Self>,
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent;
}

impl<G> FaceNormal for G
where
    G: FaceCentroid + GraphGeometry,
    G::Vertex: AsPosition,
    Vector<VertexPosition<G>>: Cross<Output = Vector<VertexPosition<G>>>,
    VertexPosition<G>: EuclideanSpace,
{
    fn normal<R, M>(ring: R) -> Result<Vector<VertexPosition<Self>>, GraphError>
    where
        R: Ring<M, Self>,
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent,
    {
        let (a, b) =
            FromItems::from_items(ring.vertices().take(2).map(|vertex| *vertex.position()))
                .expect_consistent();
        let c = G::centroid(ring)?;
        let ab = a - b;
        let bc = b - c;
        ab.cross(bc).normalize().ok_or_else(|| GraphError::Geometry)
    }
}

pub trait FacePlane: GraphGeometry
where
    Self::Vertex: AsPosition,
    VertexPosition<Self>: FiniteDimensional<N = U3>,
{
    fn plane<R, M>(ring: R) -> Result<Plane<VertexPosition<Self>>, GraphError>
    where
        R: Ring<M, Self>,
        M: Reborrow,
        M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent;
}

// TODO: The `array` feature only supports Linux. See
//       https://github.com/olson-sean-k/theon/issues/1
#[cfg(target_os = "linux")]
mod array {
    use super::*;

    use smallvec::SmallVec;
    use theon::array::ArrayScalar;
    use theon::space::Scalar;
    use theon::{FromItems, IntoItems};

    impl<G> FacePlane for G
    where
        G: GraphGeometry,
        G::Vertex: AsPosition,
        VertexPosition<G>: EuclideanSpace + FiniteDimensional<N = U3>,
        Scalar<VertexPosition<G>>: ArrayScalar,
        Vector<VertexPosition<G>>: FromItems + IntoItems,
    {
        fn plane<R, M>(ring: R) -> Result<Plane<VertexPosition<G>>, GraphError>
        where
            R: Ring<M, Self>,
            M: Reborrow,
            M::Target: AsStorage<ArcPayload<Self>> + AsStorage<VertexPayload<Self>> + Consistent,
        {
            let points = ring
                .vertices()
                .map(|vertex| *vertex.geometry.as_position())
                .collect::<SmallVec<[_; 4]>>();
            Plane::from_points(points).ok_or_else(|| GraphError::Geometry)
        }
    }
}
<|endoftext|>


<commit_before>use mli::Forward;
use mli_conv::Conv2;
use ndarray::array;
use ndarray_image::{open_gray_image, save_gray_image};
use std::path::PathBuf;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(name = "image", about = "Loads and convolves an image as a test")]
struct Opt {
    /// File to load
    #[structopt(parse(from_os_str))]
    file: PathBuf,
    /// Output location
    #[structopt(parse(from_os_str))]
    output: PathBuf,
}

fn main() {
    let opt = Opt::from_args();
    let image = open_gray_image(opt.file).expect("unable to open input image");
    let image = image.map(|&n| n.into());
    let down_filter = array![[-1.0, -2.0, -1.0], [0.0, 0.0, 0.0], [1.0, 2.0, 1.0],];
    let right_filter = down_filter.t().to_owned();
    let down = Conv2(down_filter).forward(&image).1;
    let right = Conv2(right_filter).forward(&image).1;
    let image = (down.map(|f| f.powi(2)) + right.map(|f| f.powi(2))).map(|f| f.sqrt());
    let image = image.map(|&n| num::clamp(n, 0.0, 255.0) as u8);
    save_gray_image(opt.output, image.view()).expect("failed to write output");
}
<commit_msg>fix sobel example after revamp<commit_after>use mli::Forward;
use mli_conv::Conv2;
use ndarray::array;
use ndarray_image::{open_gray_image, save_gray_image};
use std::path::PathBuf;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(name = "image", about = "Loads and convolves an image as a test")]
struct Opt {
    /// File to load
    #[structopt(parse(from_os_str))]
    file: PathBuf,
    /// Output location
    #[structopt(parse(from_os_str))]
    output: PathBuf,
}

fn main() {
    let opt = Opt::from_args();
    let image = open_gray_image(opt.file).expect("unable to open input image");
    let image = image.map(|&n| n.into());
    let down_filter = array![[-1.0, -2.0, -1.0], [0.0, 0.0, 0.0], [1.0, 2.0, 1.0],];
    let right_filter = down_filter.t().to_owned();
    let down = Conv2::new(down_filter).forward(&image).1;
    let right = Conv2::new(right_filter).forward(&image).1;
    let image = (down.map(|f| f.powi(2)) + right.map(|f| f.powi(2))).map(|f| f.sqrt());
    let image = image.map(|&n| num::clamp(n, 0.0, 255.0) as u8);
    save_gray_image(opt.output, image.view()).expect("failed to write output");
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use glib::translate::*;

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Atom(ffi::GdkAtom);

pub const NONE: Atom = Atom(0 as *mut _);

impl Atom {
    pub fn intern(atom_name: &str) -> Atom {
        assert_initialized_main_thread!();
        unsafe { Atom(ffi::gdk_atom_intern(atom_name.to_glib_none().0, false.to_glib())) }
    }

    pub fn name(&self) -> String {
        unsafe { from_glib_full(ffi::gdk_atom_name(self.0)) }
    }
}

impl GlibPtrDefault for Atom {
    type GlibType = *mut ffi::GdkAtom;
}

impl<'a> ToGlibPtr<'a, ffi::GdkAtom> for Atom {
    type Storage = ();

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, ffi::GdkAtom, Atom> {
        Stash(self.0, ())
    }
}

impl FromGlibPtrNone<*mut ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::GdkAtom) -> Atom { Atom(*ptr) }
}

impl FromGlibPtrFull<*mut ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_full(_: *mut ffi::GdkAtom) -> Atom { unimplemented!() }
}

impl FromGlibPtrNone<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_none(ptr: ffi::GdkAtom) -> Atom { Atom(ptr) }
}

impl FromGlibPtrFull<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_full(_: ffi::GdkAtom) -> Atom { unimplemented!() }
}

impl<'a> From<&'a str> for Atom {
    fn from(r: &'a str) -> Atom {
        skip_assert_initialized!();
        Atom::intern(r)
    }
}
<commit_msg>Fixed Atom container conversion<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use glib::translate::*;

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Atom(ffi::GdkAtom);

pub const NONE: Atom = Atom(0 as *mut _);

impl Atom {
    pub fn intern(atom_name: &str) -> Atom {
        assert_initialized_main_thread!();
        unsafe { Atom(ffi::gdk_atom_intern(atom_name.to_glib_none().0, false.to_glib())) }
    }

    pub fn name(&self) -> String {
        unsafe { from_glib_full(ffi::gdk_atom_name(self.0)) }
    }

    pub unsafe fn value(&self) -> usize {
        self.0 as usize
    }
}

impl GlibPtrDefault for Atom {
    type GlibType = ffi::GdkAtom;
}

impl<'a> ToGlibPtr<'a, ffi::GdkAtom> for Atom {
    type Storage = ();

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, ffi::GdkAtom, Atom> {
        Stash(self.0, ())
    }
}

impl FromGlibPtrNone<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_none(ptr: ffi::GdkAtom) -> Atom { Atom(ptr) }
}

impl FromGlibPtrFull<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_full(_: ffi::GdkAtom) -> Atom { unimplemented!() }
}

impl<'a> From<&'a str> for Atom {
    fn from(r: &'a str) -> Atom {
        skip_assert_initialized!();
        Atom::intern(r)
    }
}
<|endoftext|>