<commit_before>#![feature(test)]
#![feature(tool_lints)]

use std::env;

#[macro_export]
macro_rules! get_version_info {
    () => {{
        let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
        let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
        let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
        let crate_name = String::from(env!("CARGO_PKG_NAME"));

        let host_compiler = $crate::get_channel();
        let commit_hash = option_env!("GIT_HASH").map(|s| s.to_string());
        let commit_date = option_env!("COMMIT_DATE").map(|s| s.to_string());

        VersionInfo {
            major,
            minor,
            patch,
            host_compiler,
            commit_hash,
            commit_date,
            crate_name,
        }
    }};
}

// some code taken and adapted from RLS and cargo
pub struct VersionInfo {
    pub major: u8,
    pub minor: u8,
    pub patch: u16,
    pub host_compiler: Option<String>,
    pub commit_hash: Option<String>,
    pub commit_date: Option<String>,
    pub crate_name: String,
}

impl std::fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self.commit_hash {
            Some(_) => {
                write!(
                    f,
                    "{} {}.{}.{} ({} {})",
                    self.crate_name,
                    self.major,
                    self.minor,
                    self.patch,
                    self.commit_hash.clone().unwrap_or_default().trim(),
                    self.commit_date.clone().unwrap_or_default().trim(),
                )?;
            },
            None => {
                write!(f, "{} {}.{}.{}", self.crate_name, self.major, self.minor, self.patch)?;
            },
        };
        Ok(())
    }
}

impl std::fmt::Debug for VersionInfo {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(
            f,
            "VersionInfo {{ crate_name: \"{}\", major: {}, minor: {}, patch: {}",
            self.crate_name, self.major, self.minor, self.patch,
        )?;
        match self.commit_hash {
            Some(_) => {
                write!(
                    f,
                    ", commit_hash: \"{}\", commit_date: \"{}\" }}",
                    self.commit_hash.clone().unwrap_or_default().trim(),
                    self.commit_date.clone().unwrap_or_default().trim()
                )?;
            },
            None => {
                write!(f, " }}")?;
            },
        }
        Ok(())
    }
}

pub fn get_channel() -> Option<String> {
    if let Ok(channel) = env::var("CFG_RELEASE_CHANNEL") {
        Some(channel)
    } else {
        // we could ask ${RUSTC} -Vv and do some parsing and find out
        Some(String::from("nightly"))
    }
}

pub fn get_commit_hash() -> Option<String> {
    std::process::Command::new("git")
        .args(&["rev-parse", "--short", "HEAD"])
        .output()
        .ok()
        .and_then(|r| String::from_utf8(r.stdout).ok())
}

pub fn get_commit_date() -> Option<String> {
    std::process::Command::new("git")
        .args(&["log", "-1", "--date=short", "--pretty=format:%cd"])
        .output()
        .ok()
        .and_then(|r| String::from_utf8(r.stdout).ok())
}

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

    #[test]
    fn test_struct_local() {
        let vi = get_version_info!();
        assert_eq!(vi.major, 0);
        assert_eq!(vi.minor, 1);
        assert_eq!(vi.patch, 0);
        assert_eq!(vi.crate_name, "rustc_tools_util");
        // hard to make positive tests for these since they will always change
        assert!(vi.commit_hash.is_none());
        assert!(vi.commit_date.is_none());
    }

    #[test]
    fn test_display_local() {
        let vi = get_version_info!();
        assert_eq!(vi.to_string(), "rustc_tools_util 0.1.0");
    }

    #[test]
    fn test_debug_local() {
        let vi = get_version_info!();
        let s = format!("{:?}", vi);
        assert_eq!(
            s,
            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 1, patch: 0 }"
        );
    }

}
<commit_msg>rustc_tools_util: clean up pedantic clippy warnings<commit_after>#![feature(test)]
#![feature(tool_lints)]

use std::env;

#[macro_export]
macro_rules! get_version_info {
    () => {{
        let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
        let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
        let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
        let crate_name = String::from(env!("CARGO_PKG_NAME"));

        let host_compiler = $crate::get_channel();
        let commit_hash = option_env!("GIT_HASH").map(|s| s.to_string());
        let commit_date = option_env!("COMMIT_DATE").map(|s| s.to_string());

        VersionInfo {
            major,
            minor,
            patch,
            host_compiler,
            commit_hash,
            commit_date,
            crate_name,
        }
    }};
}

// some code taken and adapted from RLS and cargo
pub struct VersionInfo {
    pub major: u8,
    pub minor: u8,
    pub patch: u16,
    pub host_compiler: Option<String>,
    pub commit_hash: Option<String>,
    pub commit_date: Option<String>,
    pub crate_name: String,
}

impl std::fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if self.commit_hash.is_some() {
            write!(
                f,
                "{} {}.{}.{} ({} {})",
                self.crate_name,
                self.major,
                self.minor,
                self.patch,
                self.commit_hash.clone().unwrap_or_default().trim(),
                self.commit_date.clone().unwrap_or_default().trim(),
            )?;
        } else {
            write!(f, "{} {}.{}.{}", self.crate_name, self.major, self.minor, self.patch)?;
        }

        Ok(())
    }
}

impl std::fmt::Debug for VersionInfo {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "VersionInfo {{ crate_name: \"{}\", major: {}, minor: {}, patch: {}",
            self.crate_name, self.major, self.minor, self.patch,
        )?;
        if self.commit_hash.is_some() {
            write!(
                f,
                ", commit_hash: \"{}\", commit_date: \"{}\" }}",
                self.commit_hash.clone().unwrap_or_default().trim(),
                self.commit_date.clone().unwrap_or_default().trim()
            )?;
        } else {
            write!(f, " }}")?;
        }

        Ok(())
    }
}

pub fn get_channel() -> Option<String> {
    if let Ok(channel) = env::var("CFG_RELEASE_CHANNEL") {
        Some(channel)
    } else {
        // we could ask ${RUSTC} -Vv and do some parsing and find out
        Some(String::from("nightly"))
    }
}

pub fn get_commit_hash() -> Option<String> {
    std::process::Command::new("git")
        .args(&["rev-parse", "--short", "HEAD"])
        .output()
        .ok()
        .and_then(|r| String::from_utf8(r.stdout).ok())
}

pub fn get_commit_date() -> Option<String> {
    std::process::Command::new("git")
        .args(&["log", "-1", "--date=short", "--pretty=format:%cd"])
        .output()
        .ok()
        .and_then(|r| String::from_utf8(r.stdout).ok())
}

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

    #[test]
    fn test_struct_local() {
        let vi = get_version_info!();
        assert_eq!(vi.major, 0);
        assert_eq!(vi.minor, 1);
        assert_eq!(vi.patch, 0);
        assert_eq!(vi.crate_name, "rustc_tools_util");
        // hard to make positive tests for these since they will always change
        assert!(vi.commit_hash.is_none());
        assert!(vi.commit_date.is_none());
    }

    #[test]
    fn test_display_local() {
        let vi = get_version_info!();
        assert_eq!(vi.to_string(), "rustc_tools_util 0.1.0");
    }

    #[test]
    fn test_debug_local() {
        let vi = get_version_info!();
        let s = format!("{:?}", vi);
        assert_eq!(
            s,
            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 1, patch: 0 }"
        );
    }

}
<|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_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 no intrinsic dimensions<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_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>//! This module contains free-standing functions for creating AST fragments out
//! of smaller pieces.
use itertools::Itertools;

use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken};

pub fn name(text: &str) -> ast::Name {
    ast_from_text(&format!("mod {};", text))
}

pub fn name_ref(text: &str) -> ast::NameRef {
    ast_from_text(&format!("fn f() {{ {}; }}", text))
}

pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
    ast_from_text(&format!("use {};", name_ref.syntax()))
}
pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path {
    path_from_text(&format!("use {}", segment.syntax()))
}
pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path {
    path_from_text(&format!("{}::{}", qual.syntax(), segment.syntax()))
}
fn path_from_text(text: &str) -> ast::Path {
    ast_from_text(text)
}

pub fn use_tree(
    path: ast::Path,
    use_tree_list: Option<ast::UseTreeList>,
    alias: Option<ast::Alias>,
) -> ast::UseTree {
    let mut buf = "use ".to_string();
    buf += &path.syntax().to_string();
    if let Some(use_tree_list) = use_tree_list {
        buf += &format!("::{}", use_tree_list.syntax());
    }
    if let Some(alias) = alias {
        buf += &format!(" {}", alias.syntax());
    }
    ast_from_text(&buf)
}

pub fn use_tree_list(use_trees: impl IntoIterator<Item = ast::UseTree>) -> ast::UseTreeList {
    let use_trees = use_trees.into_iter().map(|it| it.syntax().clone()).join(", ");
    ast_from_text(&format!("use {{{}}};", use_trees))
}

pub fn use_item(use_tree: ast::UseTree) -> ast::UseItem {
    ast_from_text(&format!("use {};", use_tree.syntax()))
}

pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordField {
    return match expr {
        Some(expr) => from_text(&format!("{}: {}", name.syntax(), expr.syntax())),
        None => from_text(&name.syntax().to_string()),
    };

    fn from_text(text: &str) -> ast::RecordField {
        ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text))
    }
}

pub fn block_expr(
    stmts: impl IntoIterator<Item = ast::Stmt>,
    tail_expr: Option<ast::Expr>,
) -> ast::BlockExpr {
    let mut text = "{\n".to_string();
    for stmt in stmts.into_iter() {
        text += &format!("    {}\n", stmt.syntax());
    }
    if let Some(tail_expr) = tail_expr {
        text += &format!("    {}\n", tail_expr.syntax())
    }
    text += "}";
    ast_from_text(&format!("fn f() {}", text))
}

pub fn block_from_expr(e: ast::Expr) -> ast::Block {
    return from_text(&format!("{{ {} }}", e.syntax()));

    fn from_text(text: &str) -> ast::Block {
        ast_from_text(&format!("fn f() {}", text))
    }
}

pub fn expr_unit() -> ast::Expr {
    expr_from_text("()")
}
pub fn expr_empty_block() -> ast::Expr {
    expr_from_text("{}")
}
pub fn expr_unimplemented() -> ast::Expr {
    expr_from_text("unimplemented!()")
}
pub fn expr_path(path: ast::Path) -> ast::Expr {
    expr_from_text(&path.syntax().to_string())
}
pub fn expr_continue() -> ast::Expr {
    expr_from_text("continue")
}
pub fn expr_break() -> ast::Expr {
    expr_from_text("break")
}
pub fn expr_return() -> ast::Expr {
    expr_from_text("return")
}
pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
    expr_from_text(&format!("match {} {}", expr.syntax(), match_arm_list.syntax()))
}
pub fn expr_if(condition: ast::Expr, then_branch: ast::BlockExpr) -> ast::Expr {
    expr_from_text(&format!("if {} {}", condition.syntax(), then_branch.syntax()))
}
pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
    let token = token(op);
    expr_from_text(&format!("{}{}", token, expr.syntax()))
}
fn expr_from_text(text: &str) -> ast::Expr {
    ast_from_text(&format!("const C: () = {};", text))
}

pub fn try_expr_from_text(text: &str) -> Option<ast::Expr> {
    try_ast_from_text(&format!("const C: () = {};", text))
}

pub fn bind_pat(name: ast::Name) -> ast::BindPat {
    return from_text(name.text());

    fn from_text(text: &str) -> ast::BindPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn placeholder_pat() -> ast::PlaceholderPat {
    return from_text("_");

    fn from_text(text: &str) -> ast::PlaceholderPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

/// Creates a tuple of patterns from an interator of patterns.
///
/// Invariant: `pats` must be length > 1
///
/// FIXME handle `pats` length == 1
pub fn tuple_pat(pats: impl IntoIterator<Item = ast::Pat>) -> ast::TuplePat {
    let pats_str = pats.into_iter().map(|p| p.to_string()).join(", ");
    return from_text(&format!("({})", pats_str));

    fn from_text(text: &str) -> ast::TuplePat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn tuple_struct_pat(
    path: ast::Path,
    pats: impl IntoIterator<Item = ast::Pat>,
) -> ast::TupleStructPat {
    let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(", ");
    return from_text(&format!("{}({})", path.syntax(), pats_str));

    fn from_text(text: &str) -> ast::TupleStructPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn record_pat(path: ast::Path, pats: impl IntoIterator<Item = ast::Pat>) -> ast::RecordPat {
    let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(", ");
    return from_text(&format!("{} {{ {} }}", path.syntax(), pats_str));

    fn from_text(text: &str) -> ast::RecordPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

/// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise.
pub fn path_pat(path: ast::Path) -> ast::Pat {
    let path_str = path.syntax().text().to_string();
    return from_text(path_str.as_str());
    fn from_text(text: &str) -> ast::Pat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn match_arm(pats: impl IntoIterator<Item = ast::Pat>, expr: ast::Expr) -> ast::MatchArm {
    let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(" | ");
    return from_text(&format!("{} => {}", pats_str, expr.syntax()));

    fn from_text(text: &str) -> ast::MatchArm {
        ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
    }
}

pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList {
    let arms_str = arms
        .into_iter()
        .map(|arm| {
            let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like());
            let comma = if needs_comma { "," } else { "" };
            format!("    {}{}\n", arm.syntax(), comma)
        })
        .collect::<String>();
    return from_text(&arms_str);

    fn from_text(text: &str) -> ast::MatchArmList {
        ast_from_text(&format!("fn f() {{ match () {{\n{}}} }}", text))
    }
}

pub fn where_pred(
    path: ast::Path,
    bounds: impl IntoIterator<Item = ast::TypeBound>,
) -> ast::WherePred {
    let bounds = bounds.into_iter().map(|b| b.syntax().to_string()).join(" + ");
    return from_text(&format!("{}: {}", path.syntax(), bounds));

    fn from_text(text: &str) -> ast::WherePred {
        ast_from_text(&format!("fn f() where {} {{ }}", text))
    }
}

pub fn where_clause(preds: impl IntoIterator<Item = ast::WherePred>) -> ast::WhereClause {
    let preds = preds.into_iter().map(|p| p.syntax().to_string()).join(", ");
    return from_text(preds.as_str());

    fn from_text(text: &str) -> ast::WhereClause {
        ast_from_text(&format!("fn f() where {} {{ }}", text))
    }
}

pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetStmt {
    let text = match initializer {
        Some(it) => format!("let {} = {};", pattern.syntax(), it.syntax()),
        None => format!("let {};", pattern.syntax()),
    };
    ast_from_text(&format!("fn f() {{ {} }}", text))
}
pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt {
    ast_from_text(&format!("fn f() {{ {}; }}", expr.syntax()))
}

pub fn token(kind: SyntaxKind) -> SyntaxToken {
    tokens::SOURCE_FILE
        .tree()
        .syntax()
        .descendants_with_tokens()
        .filter_map(|it| it.into_token())
        .find(|it| it.kind() == kind)
        .unwrap_or_else(|| panic!("unhandled token: {:?}", kind))
}

fn ast_from_text<N: AstNode>(text: &str) -> N {
    let parse = SourceFile::parse(text);
    let node = parse.tree().syntax().descendants().find_map(N::cast).unwrap();
    let node = node.syntax().clone();
    let node = unroot(node);
    let node = N::cast(node).unwrap();
    assert_eq!(node.syntax().text_range().start(), 0.into());
    node
}

fn try_ast_from_text<N: AstNode>(text: &str) -> Option<N> {
    let parse = SourceFile::parse(text);
    let node = parse.tree().syntax().descendants().find_map(N::cast)?;
    let node = node.syntax().clone();
    let node = unroot(node);
    let node = N::cast(node).unwrap();
    assert_eq!(node.syntax().text_range().start(), 0.into());
    Some(node)
}

fn unroot(n: SyntaxNode) -> SyntaxNode {
    SyntaxNode::new_root(n.green().clone())
}

pub mod tokens {
    use once_cell::sync::Lazy;

    use crate::{ast, AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken};

    pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> =
        Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2, !true)\n;"));

    pub fn single_space() -> SyntaxToken {
        SOURCE_FILE
            .tree()
            .syntax()
            .descendants_with_tokens()
            .filter_map(|it| it.into_token())
            .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ")
            .unwrap()
    }

    pub fn whitespace(text: &str) -> SyntaxToken {
        assert!(text.trim().is_empty());
        let sf = SourceFile::parse(text).ok().unwrap();
        sf.syntax().first_child_or_token().unwrap().into_token().unwrap()
    }

    pub fn doc_comment(text: &str) -> SyntaxToken {
        assert!(!text.trim().is_empty());
        let sf = SourceFile::parse(text).ok().unwrap();
        sf.syntax().first_child_or_token().unwrap().into_token().unwrap()
    }

    pub fn literal(text: &str) -> SyntaxToken {
        assert_eq!(text.trim(), text);
        let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {}; }}", text));
        lit.syntax().first_child_or_token().unwrap().into_token().unwrap()
    }

    pub fn single_newline() -> SyntaxToken {
        SOURCE_FILE
            .tree()
            .syntax()
            .descendants_with_tokens()
            .filter_map(|it| it.into_token())
            .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n")
            .unwrap()
    }

    pub struct WsBuilder(SourceFile);

    impl WsBuilder {
        pub fn new(text: &str) -> WsBuilder {
            WsBuilder(SourceFile::parse(text).ok().unwrap())
        }
        pub fn ws(&self) -> SyntaxToken {
            self.0.syntax().first_child_or_token().unwrap().into_token().unwrap()
        }
    }
}
<commit_msg>Simplify<commit_after>//! This module contains free-standing functions for creating AST fragments out
//! of smaller pieces.
use itertools::Itertools;

use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken};

pub fn name(text: &str) -> ast::Name {
    ast_from_text(&format!("mod {};", text))
}

pub fn name_ref(text: &str) -> ast::NameRef {
    ast_from_text(&format!("fn f() {{ {}; }}", text))
}

pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
    ast_from_text(&format!("use {};", name_ref))
}
pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path {
    path_from_text(&format!("use {}", segment))
}
pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path {
    path_from_text(&format!("{}::{}", qual, segment))
}
fn path_from_text(text: &str) -> ast::Path {
    ast_from_text(text)
}

pub fn use_tree(
    path: ast::Path,
    use_tree_list: Option<ast::UseTreeList>,
    alias: Option<ast::Alias>,
) -> ast::UseTree {
    let mut buf = "use ".to_string();
    buf += &path.syntax().to_string();
    if let Some(use_tree_list) = use_tree_list {
        buf += &format!("::{}", use_tree_list);
    }
    if let Some(alias) = alias {
        buf += &format!(" {}", alias);
    }
    ast_from_text(&buf)
}

pub fn use_tree_list(use_trees: impl IntoIterator<Item = ast::UseTree>) -> ast::UseTreeList {
    let use_trees = use_trees.into_iter().map(|it| it.syntax().clone()).join(", ");
    ast_from_text(&format!("use {{{}}};", use_trees))
}

pub fn use_item(use_tree: ast::UseTree) -> ast::UseItem {
    ast_from_text(&format!("use {};", use_tree))
}

pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordField {
    return match expr {
        Some(expr) => from_text(&format!("{}: {}", name, expr)),
        None => from_text(&name.to_string()),
    };

    fn from_text(text: &str) -> ast::RecordField {
        ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text))
    }
}

pub fn block_expr(
    stmts: impl IntoIterator<Item = ast::Stmt>,
    tail_expr: Option<ast::Expr>,
) -> ast::BlockExpr {
    let mut text = "{\n".to_string();
    for stmt in stmts.into_iter() {
        text += &format!("    {}\n", stmt);
    }
    if let Some(tail_expr) = tail_expr {
        text += &format!("    {}\n", tail_expr)
    }
    text += "}";
    ast_from_text(&format!("fn f() {}", text))
}

pub fn block_from_expr(e: ast::Expr) -> ast::Block {
    return from_text(&format!("{{ {} }}", e));

    fn from_text(text: &str) -> ast::Block {
        ast_from_text(&format!("fn f() {}", text))
    }
}

pub fn expr_unit() -> ast::Expr {
    expr_from_text("()")
}
pub fn expr_empty_block() -> ast::Expr {
    expr_from_text("{}")
}
pub fn expr_unimplemented() -> ast::Expr {
    expr_from_text("unimplemented!()")
}
pub fn expr_path(path: ast::Path) -> ast::Expr {
    expr_from_text(&path.to_string())
}
pub fn expr_continue() -> ast::Expr {
    expr_from_text("continue")
}
pub fn expr_break() -> ast::Expr {
    expr_from_text("break")
}
pub fn expr_return() -> ast::Expr {
    expr_from_text("return")
}
pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
    expr_from_text(&format!("match {} {}", expr, match_arm_list))
}
pub fn expr_if(condition: ast::Expr, then_branch: ast::BlockExpr) -> ast::Expr {
    expr_from_text(&format!("if {} {}", condition, then_branch))
}
pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
    let token = token(op);
    expr_from_text(&format!("{}{}", token, expr))
}
fn expr_from_text(text: &str) -> ast::Expr {
    ast_from_text(&format!("const C: () = {};", text))
}

pub fn try_expr_from_text(text: &str) -> Option<ast::Expr> {
    try_ast_from_text(&format!("const C: () = {};", text))
}

pub fn bind_pat(name: ast::Name) -> ast::BindPat {
    return from_text(name.text());

    fn from_text(text: &str) -> ast::BindPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn placeholder_pat() -> ast::PlaceholderPat {
    return from_text("_");

    fn from_text(text: &str) -> ast::PlaceholderPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

/// Creates a tuple of patterns from an interator of patterns.
///
/// Invariant: `pats` must be length > 1
///
/// FIXME handle `pats` length == 1
pub fn tuple_pat(pats: impl IntoIterator<Item = ast::Pat>) -> ast::TuplePat {
    let pats_str = pats.into_iter().map(|p| p.to_string()).join(", ");
    return from_text(&format!("({})", pats_str));

    fn from_text(text: &str) -> ast::TuplePat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn tuple_struct_pat(
    path: ast::Path,
    pats: impl IntoIterator<Item = ast::Pat>,
) -> ast::TupleStructPat {
    let pats_str = pats.into_iter().join(", ");
    return from_text(&format!("{}({})", path, pats_str));

    fn from_text(text: &str) -> ast::TupleStructPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn record_pat(path: ast::Path, pats: impl IntoIterator<Item = ast::Pat>) -> ast::RecordPat {
    let pats_str = pats.into_iter().join(", ");
    return from_text(&format!("{} {{ {} }}", path, pats_str));

    fn from_text(text: &str) -> ast::RecordPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

/// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise.
pub fn path_pat(path: ast::Path) -> ast::Pat {
    return from_text(&path.to_string());
    fn from_text(text: &str) -> ast::Pat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn match_arm(pats: impl IntoIterator<Item = ast::Pat>, expr: ast::Expr) -> ast::MatchArm {
    let pats_str = pats.into_iter().join(" | ");
    return from_text(&format!("{} => {}", pats_str, expr));

    fn from_text(text: &str) -> ast::MatchArm {
        ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
    }
}

pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList {
    let arms_str = arms
        .into_iter()
        .map(|arm| {
            let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like());
            let comma = if needs_comma { "," } else { "" };
            format!("    {}{}\n", arm.syntax(), comma)
        })
        .collect::<String>();
    return from_text(&arms_str);

    fn from_text(text: &str) -> ast::MatchArmList {
        ast_from_text(&format!("fn f() {{ match () {{\n{}}} }}", text))
    }
}

pub fn where_pred(
    path: ast::Path,
    bounds: impl IntoIterator<Item = ast::TypeBound>,
) -> ast::WherePred {
    let bounds = bounds.into_iter().join(" + ");
    return from_text(&format!("{}: {}", path, bounds));

    fn from_text(text: &str) -> ast::WherePred {
        ast_from_text(&format!("fn f() where {} {{ }}", text))
    }
}

pub fn where_clause(preds: impl IntoIterator<Item = ast::WherePred>) -> ast::WhereClause {
    let preds = preds.into_iter().join(", ");
    return from_text(preds.as_str());

    fn from_text(text: &str) -> ast::WhereClause {
        ast_from_text(&format!("fn f() where {} {{ }}", text))
    }
}

pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetStmt {
    let text = match initializer {
        Some(it) => format!("let {} = {};", pattern, it),
        None => format!("let {};", pattern),
    };
    ast_from_text(&format!("fn f() {{ {} }}", text))
}
pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt {
    ast_from_text(&format!("fn f() {{ {}; }}", expr))
}

pub fn token(kind: SyntaxKind) -> SyntaxToken {
    tokens::SOURCE_FILE
        .tree()
        .syntax()
        .descendants_with_tokens()
        .filter_map(|it| it.into_token())
        .find(|it| it.kind() == kind)
        .unwrap_or_else(|| panic!("unhandled token: {:?}", kind))
}

fn ast_from_text<N: AstNode>(text: &str) -> N {
    let parse = SourceFile::parse(text);
    let node = parse.tree().syntax().descendants().find_map(N::cast).unwrap();
    let node = node.syntax().clone();
    let node = unroot(node);
    let node = N::cast(node).unwrap();
    assert_eq!(node.syntax().text_range().start(), 0.into());
    node
}

fn try_ast_from_text<N: AstNode>(text: &str) -> Option<N> {
    let parse = SourceFile::parse(text);
    let node = parse.tree().syntax().descendants().find_map(N::cast)?;
    let node = node.syntax().clone();
    let node = unroot(node);
    let node = N::cast(node).unwrap();
    assert_eq!(node.syntax().text_range().start(), 0.into());
    Some(node)
}

fn unroot(n: SyntaxNode) -> SyntaxNode {
    SyntaxNode::new_root(n.green().clone())
}

pub mod tokens {
    use once_cell::sync::Lazy;

    use crate::{ast, AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken};

    pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> =
        Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2, !true)\n;"));

    pub fn single_space() -> SyntaxToken {
        SOURCE_FILE
            .tree()
            .syntax()
            .descendants_with_tokens()
            .filter_map(|it| it.into_token())
            .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ")
            .unwrap()
    }

    pub fn whitespace(text: &str) -> SyntaxToken {
        assert!(text.trim().is_empty());
        let sf = SourceFile::parse(text).ok().unwrap();
        sf.syntax().first_child_or_token().unwrap().into_token().unwrap()
    }

    pub fn doc_comment(text: &str) -> SyntaxToken {
        assert!(!text.trim().is_empty());
        let sf = SourceFile::parse(text).ok().unwrap();
        sf.syntax().first_child_or_token().unwrap().into_token().unwrap()
    }

    pub fn literal(text: &str) -> SyntaxToken {
        assert_eq!(text.trim(), text);
        let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {}; }}", text));
        lit.syntax().first_child_or_token().unwrap().into_token().unwrap()
    }

    pub fn single_newline() -> SyntaxToken {
        SOURCE_FILE
            .tree()
            .syntax()
            .descendants_with_tokens()
            .filter_map(|it| it.into_token())
            .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n")
            .unwrap()
    }

    pub struct WsBuilder(SourceFile);

    impl WsBuilder {
        pub fn new(text: &str) -> WsBuilder {
            WsBuilder(SourceFile::parse(text).ok().unwrap())
        }
        pub fn ws(&self) -> SyntaxToken {
            self.0.syntax().first_child_or_token().unwrap().into_token().unwrap()
        }
    }
}
<|endoftext|>


<commit_before>//! (De)serializable types for the events in the [Matrix](https://matrix.org) specification.
//! These types are used by other Ruma crates.
//!
//! All data exchanged over Matrix is expressed as an event.
//! Different event types represent different actions, such as joining a room or sending a message.
//! Events are stored and transmitted as simple JSON structures.
//! While anyone can create a new event type for their own purposes, the Matrix specification
//! defines a number of event types which are considered core to the protocol, and Matrix clients
//! and servers must understand their semantics.
//! This module contains Rust types for each of the event types defined by the specification and
//! facilities for extending the event system for custom event types.
//!
//! # Event types
//!
//! This module includes a Rust enum called [`EventType`], which provides a simple enumeration of
//! all the event types defined by the Matrix specification. Matrix event types are serialized to
//! JSON strings in [reverse domain name
//! notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation), although the core event
//! types all use the special "m" TLD, e.g. `m.room.message`.
//!
//! # Core event types
//!
//! This module includes Rust types for every one of the event types in the Matrix specification.
//! To better organize the crate, these types live in separate modules with a hierarchy that
//! matches the reverse domain name notation of the event type.
//! For example, the `m.room.message` event lives at
//! `ruma_common::events::::room::message::MessageLikeEvent`. Each type's module also contains a
//! Rust type for that event type's `content` field, and any other supporting types required by the
//! event's other fields.
//!
//! # Extending Ruma with custom events
//!
//! For our examples we will start with a simple custom state event. `ruma_event`
//! specifies the state event's `type` and it's [`kind`](EventKind).
//!
//! ```rust
//! use ruma_common::events::macros::EventContent;
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
//! #[ruma_event(type = "org.example.event", kind = State)]
//! pub struct ExampleContent {
//!     field: String,
//! }
//! ```
//!
//! This can be used with events structs, such as passing it into
//! `ruma::api::client::state::send_state_event`'s `Request`.
//!
//! As a more advanced example we create a reaction message event. For this event we will use a
//! [`SyncMessageLikeEvent`] struct but any [`MessageLikeEvent`] struct would work.
//!
//! ```rust
//! use ruma_common::events::{macros::EventContent, SyncMessageLikeEvent};
//! use ruma_common::EventId;
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Clone, Debug, Deserialize, Serialize)]
//! #[serde(tag = "rel_type")]
//! pub enum RelatesTo {
//!     #[serde(rename = "m.annotation")]
//!     Annotation {
//!         /// The event this reaction relates to.
//!         event_id: Box<EventId>,
//!         /// The displayable content of the reaction.
//!         key: String,
//!     },
//!
//!     /// Since this event is not fully specified in the Matrix spec
//!     /// it may change or types may be added, we are ready!
//!     #[serde(rename = "m.whatever")]
//!     Whatever,
//! }
//!
//! /// The payload for our reaction event.
//! #[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
//! #[ruma_event(type = "m.reaction", kind = MessageLike)]
//! pub struct ReactionEventContent {
//!     #[serde(rename = "m.relates_to")]
//!     pub relates_to: RelatesTo,
//! }
//!
//! let json = serde_json::json!({
//!     "content": {
//!         "m.relates_to": {
//!             "event_id": "$xxxx-xxxx",
//!             "key": "👍",
//!             "rel_type": "m.annotation"
//!         }
//!     },
//!     "event_id": "$xxxx-xxxx",
//!     "origin_server_ts": 1,
//!     "sender": "@someone:example.org",
//!     "type": "m.reaction",
//!     "unsigned": {
//!         "age": 85
//!     }
//! });
//!
//! // The downside of this event is we cannot use it with event enums,
//! // but could be deserialized from a `Raw<_>` that has failed to deserialize.
//! matches::assert_matches!(
//!     serde_json::from_value::<SyncMessageLikeEvent<ReactionEventContent>>(json),
//!     Ok(SyncMessageLikeEvent {
//!         content: ReactionEventContent {
//!             relates_to: RelatesTo::Annotation { key, .. },
//!         },
//!         ..
//!     }) if key == "👍"
//! );
//! ```
//!
//! # Serialization and deserialization
//!
//! All concrete event types in this module can be serialized via the `Serialize` trait from
//! [serde](https://serde.rs/) and can be deserialized from a `Raw<EventType>`. In order to
//! handle incoming data that may not conform to this module's strict definitions of event
//! structures, deserialization will return `Raw::Err` on error. This error covers both
//! structurally invalid JSON data as well as structurally valid JSON that doesn't fulfill
//! additional constraints the matrix specification defines for some event types. The error exposes
//! the deserialized `serde_json::Value` so that developers can still work with the received
//! event data. This makes it possible to deserialize a collection of events without the entire
//! collection failing to deserialize due to a single invalid event. The "content" type for each
//! event also implements `Serialize` and either `TryFromRaw` (enabling usage as
//! `Raw<ContentType>` for dedicated content types) or `Deserialize` (when the content is a
//! type alias), allowing content to be converted to and from JSON independently of the surrounding
//! event structure, if needed.

use serde::{de::IgnoredAny, Deserialize, Serializer};

use self::room::redaction::SyncRoomRedactionEvent;
use crate::{EventEncryptionAlgorithm, RoomVersionId};

// Needs to be public for trybuild tests
#[doc(hidden)]
pub mod _custom;
mod content;
mod enums;
mod kinds;
mod unsigned;

/// Re-export of all the derives needed to create your own event types.
pub mod macros {
    pub use ruma_macros::{Event, EventContent};
}

#[cfg(feature = "unstable-msc3246")]
pub mod audio;
pub mod call;
pub mod direct;
pub mod dummy;
#[cfg(feature = "unstable-msc1767")]
pub mod emote;
#[cfg(feature = "unstable-msc3551")]
pub mod file;
pub mod forwarded_room_key;
pub mod fully_read;
pub mod ignored_user_list;
#[cfg(feature = "unstable-msc3552")]
pub mod image;
pub mod key;
#[cfg(feature = "unstable-msc3488")]
pub mod location;
#[cfg(feature = "unstable-msc1767")]
pub mod message;
#[cfg(feature = "unstable-msc1767")]
pub mod notice;
#[cfg(feature = "unstable-pdu")]
pub mod pdu;
pub mod policy;
pub mod presence;
pub mod push_rules;
#[cfg(feature = "unstable-msc2677")]
pub mod reaction;
pub mod receipt;
#[cfg(feature = "unstable-msc2675")]
pub mod relation;
pub mod room;
pub mod room_key;
pub mod room_key_request;
pub mod secret;
pub mod space;
pub mod sticker;
pub mod tag;
pub mod typing;
#[cfg(feature = "unstable-msc3553")]
pub mod video;
#[cfg(feature = "unstable-msc3245")]
pub mod voice;

#[cfg(feature = "unstable-msc2675")]
pub use self::relation::Relations;
pub use self::{
    content::*,
    enums::*,
    kinds::*,
    unsigned::{MessageLikeUnsigned, RedactedUnsigned, StateUnsigned},
};

/// Trait to define the behavior of redacting an event.
pub trait Redact {
    /// The redacted form of the event.
    type Redacted;

    /// Transforms `self` into a redacted form (removing most fields) according to the spec.
    ///
    /// A small number of events have room-version specific redaction behavior, so a version has to
    /// be specified.
    fn redact(self, redaction: SyncRoomRedactionEvent, version: &RoomVersionId) -> Self::Redacted;
}

/// Trait to define the behavior of redact an event's content object.
pub trait RedactContent {
    /// The redacted form of the event's content.
    type Redacted;

    /// Transform `self` into a redacted form (removing most or all fields) according to the spec.
    ///
    /// A small number of events have room-version specific redaction behavior, so a version has to
    /// be specified.
    ///
    /// Where applicable, it is preferred to use [`Redact::redact`] on the outer event.
    fn redact(self, version: &RoomVersionId) -> Self::Redacted;
}

/// Helper struct to determine the event kind from a `serde_json::value::RawValue`.
#[doc(hidden)]
#[derive(Deserialize)]
#[allow(clippy::exhaustive_structs)]
pub struct EventTypeDeHelper<'a> {
    #[serde(borrow, rename = "type")]
    pub ev_type: std::borrow::Cow<'a, str>,
}

/// Helper struct to determine if an event has been redacted.
#[doc(hidden)]
#[derive(Deserialize)]
#[allow(clippy::exhaustive_structs)]
pub struct RedactionDeHelper {
    /// Used to check whether redacted_because exists.
    pub unsigned: Option<UnsignedDeHelper>,
}

#[doc(hidden)]
#[derive(Deserialize)]
#[allow(clippy::exhaustive_structs)]
pub struct UnsignedDeHelper {
    /// This is the field that signals an event has been redacted.
    pub redacted_because: Option<IgnoredAny>,
}

/// Helper function for erroring when trying to serialize an event enum _Custom variant that can
/// only be created by deserializing from an unknown event type.
#[doc(hidden)]
#[allow(clippy::ptr_arg)]
pub fn serialize_custom_event_error<T, S: Serializer>(_: &T, _: S) -> Result<S::Ok, S::Error> {
    Err(serde::ser::Error::custom(
        "Failed to serialize event [content] enum: Unknown event type.\n\
         To send custom events, turn them into `Raw<EnumType>` by going through
         `serde_json::value::to_raw_value` and `Raw::from_json`.",
    ))
}
<commit_msg>events: Clean up module documentation<commit_after>//! (De)serializable types for the events in the [Matrix](https://matrix.org) specification.
//! These types are used by other Ruma crates.
//!
//! All data exchanged over Matrix is expressed as an event.
//! Different event types represent different actions, such as joining a room or sending a message.
//! Events are stored and transmitted as simple JSON structures.
//! While anyone can create a new event type for their own purposes, the Matrix specification
//! defines a number of event types which are considered core to the protocol.
//! This module contains Rust types for all of the event types defined by the specification and
//! facilities for extending the event system for custom event types.
//!
//! # Core event types
//!
//! This module includes Rust types for all event types in the Matrix specification.
//! To better organize the crate, these types live in separate modules with a hierarchy that matches
//! the reverse domain name notation of the event type. For example, the `m.room.message` event
//! lives at `ruma::events::room::message::RoomMessageEvent`. Each type's module also contains a
//! Rust type for that event type's `content` field, and any other supporting types required by the
//! event's other fields.
//!
//! # Extending Ruma with custom events
//!
//! For our examples we will start with a simple custom state event. `ruma_event`
//! specifies the state event's `type` and it's [`kind`](EventKind).
//!
//! ```rust
//! use ruma_common::events::macros::EventContent;
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
//! #[ruma_event(type = "org.example.event", kind = State)]
//! pub struct ExampleContent {
//!     field: String,
//! }
//! ```
//!
//! This can be used with events structs, such as passing it into
//! `ruma::api::client::state::send_state_event`'s `Request`.
//!
//! As a more advanced example we create a reaction message event. For this event we will use a
//! [`SyncMessageLikeEvent`] struct but any [`MessageLikeEvent`] struct would work.
//!
//! ```rust
//! use ruma_common::events::{macros::EventContent, SyncMessageLikeEvent};
//! use ruma_common::EventId;
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Clone, Debug, Deserialize, Serialize)]
//! #[serde(tag = "rel_type")]
//! pub enum RelatesTo {
//!     #[serde(rename = "m.annotation")]
//!     Annotation {
//!         /// The event this reaction relates to.
//!         event_id: Box<EventId>,
//!         /// The displayable content of the reaction.
//!         key: String,
//!     },
//!
//!     /// Since this event is not fully specified in the Matrix spec
//!     /// it may change or types may be added, we are ready!
//!     #[serde(rename = "m.whatever")]
//!     Whatever,
//! }
//!
//! /// The payload for our reaction event.
//! #[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
//! #[ruma_event(type = "m.reaction", kind = MessageLike)]
//! pub struct ReactionEventContent {
//!     #[serde(rename = "m.relates_to")]
//!     pub relates_to: RelatesTo,
//! }
//!
//! let json = serde_json::json!({
//!     "content": {
//!         "m.relates_to": {
//!             "event_id": "$xxxx-xxxx",
//!             "key": "👍",
//!             "rel_type": "m.annotation"
//!         }
//!     },
//!     "event_id": "$xxxx-xxxx",
//!     "origin_server_ts": 1,
//!     "sender": "@someone:example.org",
//!     "type": "m.reaction",
//!     "unsigned": {
//!         "age": 85
//!     }
//! });
//!
//! // The downside of this event is we cannot use it with event enums,
//! // but could be deserialized from a `Raw<_>` that has failed to deserialize.
//! matches::assert_matches!(
//!     serde_json::from_value::<SyncMessageLikeEvent<ReactionEventContent>>(json),
//!     Ok(SyncMessageLikeEvent {
//!         content: ReactionEventContent {
//!             relates_to: RelatesTo::Annotation { key, .. },
//!         },
//!         ..
//!     }) if key == "👍"
//! );
//! ```

use serde::{de::IgnoredAny, Deserialize, Serializer};

use self::room::redaction::SyncRoomRedactionEvent;
use crate::{EventEncryptionAlgorithm, RoomVersionId};

// Needs to be public for trybuild tests
#[doc(hidden)]
pub mod _custom;
mod content;
mod enums;
mod kinds;
mod unsigned;

/// Re-export of all the derives needed to create your own event types.
pub mod macros {
    pub use ruma_macros::{Event, EventContent};
}

#[cfg(feature = "unstable-msc3246")]
pub mod audio;
pub mod call;
pub mod direct;
pub mod dummy;
#[cfg(feature = "unstable-msc1767")]
pub mod emote;
#[cfg(feature = "unstable-msc3551")]
pub mod file;
pub mod forwarded_room_key;
pub mod fully_read;
pub mod ignored_user_list;
#[cfg(feature = "unstable-msc3552")]
pub mod image;
pub mod key;
#[cfg(feature = "unstable-msc3488")]
pub mod location;
#[cfg(feature = "unstable-msc1767")]
pub mod message;
#[cfg(feature = "unstable-msc1767")]
pub mod notice;
#[cfg(feature = "unstable-pdu")]
pub mod pdu;
pub mod policy;
pub mod presence;
pub mod push_rules;
#[cfg(feature = "unstable-msc2677")]
pub mod reaction;
pub mod receipt;
#[cfg(feature = "unstable-msc2675")]
pub mod relation;
pub mod room;
pub mod room_key;
pub mod room_key_request;
pub mod secret;
pub mod space;
pub mod sticker;
pub mod tag;
pub mod typing;
#[cfg(feature = "unstable-msc3553")]
pub mod video;
#[cfg(feature = "unstable-msc3245")]
pub mod voice;

#[cfg(feature = "unstable-msc2675")]
pub use self::relation::Relations;
pub use self::{
    content::*,
    enums::*,
    kinds::*,
    unsigned::{MessageLikeUnsigned, RedactedUnsigned, StateUnsigned},
};

/// Trait to define the behavior of redacting an event.
pub trait Redact {
    /// The redacted form of the event.
    type Redacted;

    /// Transforms `self` into a redacted form (removing most fields) according to the spec.
    ///
    /// A small number of events have room-version specific redaction behavior, so a version has to
    /// be specified.
    fn redact(self, redaction: SyncRoomRedactionEvent, version: &RoomVersionId) -> Self::Redacted;
}

/// Trait to define the behavior of redact an event's content object.
pub trait RedactContent {
    /// The redacted form of the event's content.
    type Redacted;

    /// Transform `self` into a redacted form (removing most or all fields) according to the spec.
    ///
    /// A small number of events have room-version specific redaction behavior, so a version has to
    /// be specified.
    ///
    /// Where applicable, it is preferred to use [`Redact::redact`] on the outer event.
    fn redact(self, version: &RoomVersionId) -> Self::Redacted;
}

/// Helper struct to determine the event kind from a `serde_json::value::RawValue`.
#[doc(hidden)]
#[derive(Deserialize)]
#[allow(clippy::exhaustive_structs)]
pub struct EventTypeDeHelper<'a> {
    #[serde(borrow, rename = "type")]
    pub ev_type: std::borrow::Cow<'a, str>,
}

/// Helper struct to determine if an event has been redacted.
#[doc(hidden)]
#[derive(Deserialize)]
#[allow(clippy::exhaustive_structs)]
pub struct RedactionDeHelper {
    /// Used to check whether redacted_because exists.
    pub unsigned: Option<UnsignedDeHelper>,
}

#[doc(hidden)]
#[derive(Deserialize)]
#[allow(clippy::exhaustive_structs)]
pub struct UnsignedDeHelper {
    /// This is the field that signals an event has been redacted.
    pub redacted_because: Option<IgnoredAny>,
}

/// Helper function for erroring when trying to serialize an event enum _Custom variant that can
/// only be created by deserializing from an unknown event type.
#[doc(hidden)]
#[allow(clippy::ptr_arg)]
pub fn serialize_custom_event_error<T, S: Serializer>(_: &T, _: S) -> Result<S::Ok, S::Error> {
    Err(serde::ser::Error::custom(
        "Failed to serialize event [content] enum: Unknown event type.\n\
         To send custom events, turn them into `Raw<EnumType>` by going through
         `serde_json::value::to_raw_value` and `Raw::from_json`.",
    ))
}
<|endoftext|>


<commit_before>use std::f32::{MAX, MIN};
use std::f32::consts::{PI};
use std::sync::{Arc};

use cgmath;
use cgmath::{Matrix, Matrix3, Matrix4, Vector3, Vector4, SquareMatrix, EuclideanSpace, InnerSpace, Rad};
use rand::{SeedableRng, StdRng};
use rand::distributions::{IndependentSample, Range};

use context::{Context};
use debug::{UnlitModel, UnlitUniforms};
use model::{Model};
use physics::{PhysicsFrame};
use render::render_context::{ModelId, DEPTH_DIMENSION};
use render::render_uniforms::{RenderUniforms};
use render::uniform_wrappers::{UMatrix4, UVector3};

pub struct RenderFrame {
	pub id: u64,
	pub models: Vec<(Arc<Model>, RenderUniforms)>,
	pub reverse_light_direction: UVector3,

	// DEBUG
	pub unlit_models: Vec<(Arc<UnlitModel>, UnlitUniforms)>,
}

impl RenderFrame {
	pub fn new(context: Arc<Context>, physics_frame: Arc<PhysicsFrame>) -> RenderFrame {
		let light_direction = physics_frame.light_direction;
		let reverse_light_direction = light_direction * -1.0;

		let shadow_view_projection = {
			let corners = physics_frame.camera.view_corners();

			// TODO: this should be constant/held somewhere
			//
			let shadow_width = {
				let outside_length:  f32 = (corners[4] - corners[1]).magnitude();
				let diagonal_length: f32 = (corners[1] - corners[0]).magnitude();
				outside_length.max(diagonal_length)
			};

			let up = Vector3::unit_y();
			let right = light_direction.cross(up).normalize();
			let up = right.cross(light_direction).normalize();

			let rotation_transposed = Matrix3::from_cols(right, up, reverse_light_direction);
			let rotation = rotation_transposed.transpose();

			// TODO: do something correct instead of this
			//
			let geometry_corners: Vec<Vector3<f32>> = vec![
				Vector3::new(-20.0,  0.0, -20.0),
				Vector3::new( 20.0,  0.0, -20.0),
				Vector3::new(-20.0,  0.0,  20.0),
				Vector3::new( 20.0,  0.0,  20.0),
				Vector3::new(-20.0, 10.0, -20.0),
				Vector3::new( 20.0, 10.0, -20.0),
				Vector3::new(-20.0, 10.0,  20.0),
				Vector3::new( 20.0, 10.0,  20.0)
			];
			let corners = corners.iter().chain(geometry_corners.iter());
			let transformed_corners = corners.map(|&v| rotation * v);

			let mut min_x = MAX;
			let mut min_y = MAX;
			let mut min_z = MAX;
			let mut max_z = MIN;
			for corner in transformed_corners {
				if corner.x < min_x { min_x = corner.x }
				if corner.y < min_y { min_y = corner.y }
				if corner.z < min_z { min_z = corner.z }
				if corner.z > max_z { max_z = corner.z }
			}

			let world_units_per_texel = shadow_width / (DEPTH_DIMENSION as f32);
			min_x = (min_x / world_units_per_texel).floor() * world_units_per_texel;
			min_y = (min_y / world_units_per_texel).floor() * world_units_per_texel;

			let projection = cgmath::ortho(
				min_x,
				min_x + shadow_width,
				min_y,
				min_y + shadow_width,
				-max_z,
				-min_z
			);

			let rotation = Matrix4::from_cols(
				rotation_transposed.x.extend(0.0),
				rotation_transposed.y.extend(0.0),
				rotation_transposed.z.extend(0.0),
				Vector4::new(0.0, 0.0, 0.0, 1.0)
			).transpose();
			projection * rotation
		};

		let view       = physics_frame.camera.view.clone();
		let projection = physics_frame.camera.projection.clone();
		let view_projection = projection * view;

		let scene_uniforms = RenderUniforms {
			shadow:                  UMatrix4(shadow_view_projection),
			model:                   UMatrix4(Matrix4::identity()),
			model_view_projection:   UMatrix4(view_projection),
		};

		let translation = Matrix4::from_translation(physics_frame.player_position.to_vec());

		let up                  = Vector3::new(0f32, 1f32, 0f32);
		let flat_view_direction = (Vector3 { y: 0f32, .. physics_frame.get_view_direction() }).normalize();
		let right               = flat_view_direction.cross(up).normalize();
		let up                  = right.cross(flat_view_direction);
		let rotation = Matrix4::from_cols(
			right.extend(0f32),
			up.extend(0f32),
			(flat_view_direction * -1f32).extend(0f32),
			Vector4::unit_w());

		let model = translation * rotation;
		let model_view_projection = view_projection * model;
		let shadow = shadow_view_projection * model;

		let player_uniforms = RenderUniforms {
			shadow:                  UMatrix4(shadow),
			model:                   UMatrix4(model),
			model_view_projection:   UMatrix4(model_view_projection),
		};

		let mut models = vec![
			(context.render.models.get(&ModelId::Scene).unwrap().clone(), scene_uniforms.clone()),
			(context.render.models.get(&ModelId::Player).unwrap().clone(), player_uniforms),
		];

		{ // TODO: all this is constant
			const D: f32 = 8f32;
			const A: f32 = 40f32;

			let seed: &[_] = &[2, 2, 2, 2];
			let mut rng: StdRng = SeedableRng::from_seed(seed);
			let range = Range::new(0f32, PI * 0.5);

			let zs = [D * -3.0, D * 3.0, D * -2.0, D * 2.0, D, -D, 0.0, A, -A];

			for &z in &zs {
				let transform =
					Matrix4::from_translation(Vector3::new(A, 0.0, z)) *
					Matrix4::from_angle_y(Rad{ s: range.ind_sample(&mut rng) });

				let uniforms = RenderUniforms {
					shadow:                UMatrix4(shadow_view_projection * transform),
					model:                 UMatrix4(transform),
					model_view_projection: UMatrix4(view_projection * transform),
				};
				models.push((context.render.models.get(&ModelId::Tree).unwrap().clone(), uniforms));
			}
		}

		for chain in &physics_frame.ik_chains {
			let transforms = chain.visible_joint_transforms();
			for joint in transforms {
				let shadow = shadow_view_projection * joint;
				let mvp = view_projection * joint;

				let uniforms = RenderUniforms {
					shadow:                  UMatrix4(shadow),
					model:                   UMatrix4(joint),
					model_view_projection:   UMatrix4(mvp),
				};
				models.push((context.render.models.get(&ModelId::IKModel).unwrap().clone(), uniforms));
			}
		}

		let unlit_models = {
			let scale = Matrix4::from_scale(3.0);
			let smvp = model_view_projection * scale;
			let svp  =       view_projection * scale;
			let scene_uniforms  = UnlitUniforms { model_view_projection: UMatrix4(smvp) };
			let player_uniforms = UnlitUniforms { model_view_projection: UMatrix4(svp) };

			vec![
				(context.render.unlit_models.get(&ModelId::Gnomon).unwrap().clone(), scene_uniforms),
				(context.render.unlit_models.get(&ModelId::Gnomon).unwrap().clone(), player_uniforms),
			]
		};

		RenderFrame {
			id: physics_frame.frame_counter,
			models: models,
			reverse_light_direction: UVector3(reverse_light_direction),
			unlit_models: unlit_models,
		}
	}
}
<commit_msg>Add debug gnomons to ik joints<commit_after>use std::f32::{MAX, MIN};
use std::f32::consts::{PI};
use std::sync::{Arc};

use cgmath;
use cgmath::{Matrix, Matrix3, Matrix4, Vector3, Vector4, SquareMatrix, EuclideanSpace, InnerSpace, Rad};
use rand::{SeedableRng, StdRng};
use rand::distributions::{IndependentSample, Range};

use context::{Context};
use debug::{UnlitModel, UnlitUniforms};
use model::{Model};
use physics::{PhysicsFrame};
use render::render_context::{ModelId, DEPTH_DIMENSION};
use render::render_uniforms::{RenderUniforms};
use render::uniform_wrappers::{UMatrix4, UVector3};

pub struct RenderFrame {
	pub id: u64,
	pub models: Vec<(Arc<Model>, RenderUniforms)>,
	pub reverse_light_direction: UVector3,

	// DEBUG
	pub unlit_models: Vec<(Arc<UnlitModel>, UnlitUniforms)>,
}

impl RenderFrame {
	pub fn new(context: Arc<Context>, physics_frame: Arc<PhysicsFrame>) -> RenderFrame {
		let light_direction = physics_frame.light_direction;
		let reverse_light_direction = light_direction * -1.0;

		let shadow_view_projection = {
			let corners = physics_frame.camera.view_corners();

			// TODO: this should be constant/held somewhere
			//
			let shadow_width = {
				let outside_length:  f32 = (corners[4] - corners[1]).magnitude();
				let diagonal_length: f32 = (corners[1] - corners[0]).magnitude();
				outside_length.max(diagonal_length)
			};

			let up = Vector3::unit_y();
			let right = light_direction.cross(up).normalize();
			let up = right.cross(light_direction).normalize();

			let rotation_transposed = Matrix3::from_cols(right, up, reverse_light_direction);
			let rotation = rotation_transposed.transpose();

			// TODO: do something correct instead of this
			//
			let geometry_corners: Vec<Vector3<f32>> = vec![
				Vector3::new(-20.0,  0.0, -20.0),
				Vector3::new( 20.0,  0.0, -20.0),
				Vector3::new(-20.0,  0.0,  20.0),
				Vector3::new( 20.0,  0.0,  20.0),
				Vector3::new(-20.0, 10.0, -20.0),
				Vector3::new( 20.0, 10.0, -20.0),
				Vector3::new(-20.0, 10.0,  20.0),
				Vector3::new( 20.0, 10.0,  20.0)
			];
			let corners = corners.iter().chain(geometry_corners.iter());
			let transformed_corners = corners.map(|&v| rotation * v);

			let mut min_x = MAX;
			let mut min_y = MAX;
			let mut min_z = MAX;
			let mut max_z = MIN;
			for corner in transformed_corners {
				if corner.x < min_x { min_x = corner.x }
				if corner.y < min_y { min_y = corner.y }
				if corner.z < min_z { min_z = corner.z }
				if corner.z > max_z { max_z = corner.z }
			}

			let world_units_per_texel = shadow_width / (DEPTH_DIMENSION as f32);
			min_x = (min_x / world_units_per_texel).floor() * world_units_per_texel;
			min_y = (min_y / world_units_per_texel).floor() * world_units_per_texel;

			let projection = cgmath::ortho(
				min_x,
				min_x + shadow_width,
				min_y,
				min_y + shadow_width,
				-max_z,
				-min_z
			);

			let rotation = Matrix4::from_cols(
				rotation_transposed.x.extend(0.0),
				rotation_transposed.y.extend(0.0),
				rotation_transposed.z.extend(0.0),
				Vector4::new(0.0, 0.0, 0.0, 1.0)
			).transpose();
			projection * rotation
		};

		let view       = physics_frame.camera.view.clone();
		let projection = physics_frame.camera.projection.clone();
		let view_projection = projection * view;

		let scene_uniforms = RenderUniforms {
			shadow:                  UMatrix4(shadow_view_projection),
			model:                   UMatrix4(Matrix4::identity()),
			model_view_projection:   UMatrix4(view_projection),
		};

		let translation = Matrix4::from_translation(physics_frame.player_position.to_vec());

		let up                  = Vector3::new(0f32, 1f32, 0f32);
		let flat_view_direction = (Vector3 { y: 0f32, .. physics_frame.get_view_direction() }).normalize();
		let right               = flat_view_direction.cross(up).normalize();
		let up                  = right.cross(flat_view_direction);
		let rotation = Matrix4::from_cols(
			right.extend(0f32),
			up.extend(0f32),
			(flat_view_direction * -1f32).extend(0f32),
			Vector4::unit_w());

		let model = translation * rotation;
		let model_view_projection = view_projection * model;
		let shadow = shadow_view_projection * model;

		let player_uniforms = RenderUniforms {
			shadow:                  UMatrix4(shadow),
			model:                   UMatrix4(model),
			model_view_projection:   UMatrix4(model_view_projection),
		};

		let mut models = vec![
			(context.render.models.get(&ModelId::Scene).unwrap().clone(), scene_uniforms.clone()),
			(context.render.models.get(&ModelId::Player).unwrap().clone(), player_uniforms),
		];

		{ // TODO: all this is constant
			const D: f32 = 8f32;
			const A: f32 = 40f32;

			let seed: &[_] = &[2, 2, 2, 2];
			let mut rng: StdRng = SeedableRng::from_seed(seed);
			let range = Range::new(0f32, PI * 0.5);

			let zs = [D * -3.0, D * 3.0, D * -2.0, D * 2.0, D, -D, 0.0, A, -A];

			for &z in &zs {
				let transform =
					Matrix4::from_translation(Vector3::new(A, 0.0, z)) *
					Matrix4::from_angle_y(Rad{ s: range.ind_sample(&mut rng) });

				let uniforms = RenderUniforms {
					shadow:                UMatrix4(shadow_view_projection * transform),
					model:                 UMatrix4(transform),
					model_view_projection: UMatrix4(view_projection * transform),
				};
				models.push((context.render.models.get(&ModelId::Tree).unwrap().clone(), uniforms));
			}
		}

		let mut unlit_models = {
			let scale = Matrix4::from_scale(3.0);
			let smvp = model_view_projection * scale;
			let svp  =       view_projection * scale;
			let scene_uniforms  = UnlitUniforms { model_view_projection: UMatrix4(smvp) };
			let player_uniforms = UnlitUniforms { model_view_projection: UMatrix4(svp) };

			vec![
				(context.render.unlit_models.get(&ModelId::Gnomon).unwrap().clone(), scene_uniforms),
				(context.render.unlit_models.get(&ModelId::Gnomon).unwrap().clone(), player_uniforms),
			]
		};

		for chain in &physics_frame.ik_chains {
			let transforms = chain.visible_joint_transforms();
			for joint in transforms {
				let shadow = shadow_view_projection * joint;
				let mvp = view_projection * joint;

				let uniforms = RenderUniforms {
					shadow:                  UMatrix4(shadow),
					model:                   UMatrix4(joint),
					model_view_projection:   UMatrix4(mvp),
				};
				models.push((context.render.models.get(&ModelId::IKModel).unwrap().clone(), uniforms));

				let mvp = mvp * Matrix4::from_scale(2.0);

				let unlit_uniforms = UnlitUniforms { model_view_projection: UMatrix4(mvp) };

				unlit_models.push((context.render.unlit_models.get(&ModelId::Gnomon).unwrap().clone(), unlit_uniforms));
			}
		}

		RenderFrame {
			id: physics_frame.frame_counter,
			models: models,
			reverse_light_direction: UVector3(reverse_light_direction),
			unlit_models: unlit_models,
		}
	}
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use std::{
    hash::{Hash, Hasher},
    iter::successors,
    marker::PhantomData,
};

use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange};

/// A pointer to a syntax node inside a file. It can be used to remember a
/// specific node across reparses of the same file.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SyntaxNodePtr {
    pub(crate) range: TextRange,
    kind: SyntaxKind,
}

impl SyntaxNodePtr {
    pub fn new(node: &SyntaxNode) -> SyntaxNodePtr {
        SyntaxNodePtr { range: node.text_range(), kind: node.kind() }
    }

    pub fn to_node(&self, root: &SyntaxNode) -> SyntaxNode {
        assert!(root.parent().is_none());
        successors(Some(root.clone()), |node| {
            node.children().find(|it| self.range.is_subrange(&it.text_range()))
        })
        .find(|it| it.text_range() == self.range && it.kind() == self.kind)
        .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))
    }

    // pub fn range(&self) -> TextRange {
    //     self.range
    // }

    pub fn cast<N: AstNode>(self) -> Option<AstPtr<N>> {
        if !N::can_cast(self.kind) {
            return None;
        }
        Some(AstPtr { raw: self, _ty: PhantomData })
    }
}

/// Like `SyntaxNodePtr`, but remembers the type of node
#[derive(Debug)]
pub struct AstPtr<N: AstNode> {
    raw: SyntaxNodePtr,
    _ty: PhantomData<fn() -> N>,
}

impl<N: AstNode> Clone for AstPtr<N> {
    fn clone(&self) -> AstPtr<N> {
        AstPtr { raw: self.raw.clone(), _ty: PhantomData }
    }
}

impl<N: AstNode> Eq for AstPtr<N> {}

impl<N: AstNode> PartialEq for AstPtr<N> {
    fn eq(&self, other: &AstPtr<N>) -> bool {
        self.raw == other.raw
    }
}

impl<N: AstNode> Hash for AstPtr<N> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.raw.hash(state)
    }
}

impl<N: AstNode> AstPtr<N> {
    pub fn new(node: &N) -> AstPtr<N> {
        AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData }
    }

    pub fn to_node(&self, root: &SyntaxNode) -> N {
        let syntax_node = self.raw.to_node(root);
        N::cast(syntax_node).unwrap()
    }

    pub fn syntax_node_ptr(&self) -> SyntaxNodePtr {
        self.raw.clone()
    }

    pub fn cast<U: AstNode>(self) -> Option<AstPtr<U>> {
        if !U::can_cast(self.raw.kind) {
            return None;
        }
        Some(AstPtr { raw: self.raw, _ty: PhantomData })
    }
}

impl<N: AstNode> From<AstPtr<N>> for SyntaxNodePtr {
    fn from(ptr: AstPtr<N>) -> SyntaxNodePtr {
        ptr.raw
    }
}

#[test]
fn test_local_syntax_ptr() {
    use crate::{ast, AstNode, SourceFile};

    let file = SourceFile::parse("struct Foo { f: u32, }").ok().unwrap();
    let field = file.syntax().descendants().find_map(ast::RecordFieldDef::cast).unwrap();
    let ptr = SyntaxNodePtr::new(field.syntax());
    let field_syntax = ptr.to_node(file.syntax());
    assert_eq!(field.syntax(), &field_syntax);
}
<commit_msg>minor<commit_after>//! FIXME: write short doc here

use std::{
    hash::{Hash, Hasher},
    iter::successors,
    marker::PhantomData,
};

use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange};

/// A pointer to a syntax node inside a file. It can be used to remember a
/// specific node across reparses of the same file.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SyntaxNodePtr {
    pub(crate) range: TextRange,
    kind: SyntaxKind,
}

impl SyntaxNodePtr {
    pub fn new(node: &SyntaxNode) -> SyntaxNodePtr {
        SyntaxNodePtr { range: node.text_range(), kind: node.kind() }
    }

    pub fn to_node(&self, root: &SyntaxNode) -> SyntaxNode {
        assert!(root.parent().is_none());
        successors(Some(root.clone()), |node| {
            node.children().find(|it| self.range.is_subrange(&it.text_range()))
        })
        .find(|it| it.text_range() == self.range && it.kind() == self.kind)
        .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))
    }

    pub fn cast<N: AstNode>(self) -> Option<AstPtr<N>> {
        if !N::can_cast(self.kind) {
            return None;
        }
        Some(AstPtr { raw: self, _ty: PhantomData })
    }
}

/// Like `SyntaxNodePtr`, but remembers the type of node
#[derive(Debug)]
pub struct AstPtr<N: AstNode> {
    raw: SyntaxNodePtr,
    _ty: PhantomData<fn() -> N>,
}

impl<N: AstNode> Clone for AstPtr<N> {
    fn clone(&self) -> AstPtr<N> {
        AstPtr { raw: self.raw.clone(), _ty: PhantomData }
    }
}

impl<N: AstNode> Eq for AstPtr<N> {}

impl<N: AstNode> PartialEq for AstPtr<N> {
    fn eq(&self, other: &AstPtr<N>) -> bool {
        self.raw == other.raw
    }
}

impl<N: AstNode> Hash for AstPtr<N> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.raw.hash(state)
    }
}

impl<N: AstNode> AstPtr<N> {
    pub fn new(node: &N) -> AstPtr<N> {
        AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData }
    }

    pub fn to_node(&self, root: &SyntaxNode) -> N {
        let syntax_node = self.raw.to_node(root);
        N::cast(syntax_node).unwrap()
    }

    pub fn syntax_node_ptr(&self) -> SyntaxNodePtr {
        self.raw.clone()
    }

    pub fn cast<U: AstNode>(self) -> Option<AstPtr<U>> {
        if !U::can_cast(self.raw.kind) {
            return None;
        }
        Some(AstPtr { raw: self.raw, _ty: PhantomData })
    }
}

impl<N: AstNode> From<AstPtr<N>> for SyntaxNodePtr {
    fn from(ptr: AstPtr<N>) -> SyntaxNodePtr {
        ptr.raw
    }
}

#[test]
fn test_local_syntax_ptr() {
    use crate::{ast, AstNode, SourceFile};

    let file = SourceFile::parse("struct Foo { f: u32, }").ok().unwrap();
    let field = file.syntax().descendants().find_map(ast::RecordFieldDef::cast).unwrap();
    let ptr = SyntaxNodePtr::new(field.syntax());
    let field_syntax = ptr.to_node(file.syntax());
    assert_eq!(field.syntax(), &field_syntax);
}
<|endoftext|>


<commit_before>/* Sample merge sort program in Rust.
   Tested to compile with rust-0.6-f1ddb8d.
*/
extern crate benchmark;
use std::slice;
use std::comm::channel;
use std::cell::RefCell;
use benchmark::Benchmark;

fn parallel_merge_sort_helper<T:Ord+Clone+Send>(arr: ~[T]) -> ~[T] {
    let max_threads = ::std::rt::default_sched_threads();

    parallel_merge_sort(arr, 0, max_threads)
}

fn parallel_merge_sort<T:Ord+Clone+Send>(arr: ~[T], depth: uint, max_threads: uint) -> ~[T] {
    let length = arr.len();
    if length <= 1 {
        return arr.to_owned();
    }

    let middle = length / 2;
    let mut left = arr.slice(0, middle).to_owned();
    let mut right = arr.slice(middle, length).to_owned();

    if depth < max_threads {
        /* Create channel to pass the results back */
        let (sender, receiver) = channel();
        let left_cell = RefCell::new(left); // the only way to access the above mutable field
        spawn(proc() {
            // take the ref out of the cell, sort it, and send it back to the parent process
            let sorted_left =  parallel_merge_sort(left_cell.get(), depth + 1, max_threads);
            sender.send(sorted_left);
        });
        right = parallel_merge_sort(right, depth + 1, max_threads);

        left = receiver.recv();
    } else {
        left = parallel_merge_sort(left, depth, max_threads);
        right = parallel_merge_sort(right, depth, max_threads);
    }

    merge(left, right)
}

fn merge<T:Ord+Clone>(left_orig: ~[T], right_orig: ~[T]) -> ~[T] {
    let mut left = left_orig.clone();
    let mut right = right_orig.clone();
    let mut result = slice::from_elem(0, left[0].clone());

    while left.len() > 0 || right.len() > 0 {
        if left.len() > 0 && right.len() > 0 {
            if left[0] < right[0] {
                result.push(left.shift().unwrap());
            }
            else {
                result.push(right.shift().unwrap());
            }
        }
        else if left.len() > 0 {
            result.push(left.shift().unwrap());
        }
        else {
            result.push(right.shift().unwrap());
        }
    }

    return result;
}

fn main() {
    let mut bench = Benchmark::new();
    bench.run(parallel_merge_sort_helper);
}

<commit_msg>Update for rust changes<commit_after>/* Sample merge sort program in Rust.
   Tested to compile with rust-0.6-f1ddb8d.
*/
extern crate benchmark;
use std::slice;
use std::comm::channel;
use std::cell::RefCell;
use benchmark::Benchmark;

fn parallel_merge_sort_helper<T:Ord+Clone+Send>(arr: ~[T]) -> ~[T] {
    let max_threads = ::std::rt::default_sched_threads();

    parallel_merge_sort(arr, 0, max_threads)
}

fn parallel_merge_sort<T:Ord+Clone+Send>(arr: ~[T], depth: uint, max_threads: uint) -> ~[T] {
    let length = arr.len();
    if length <= 1 {
        return arr.to_owned();
    }

    let middle = length / 2;
    let mut left = arr.slice(0, middle).to_owned();
    let mut right = arr.slice(middle, length).to_owned();

    if depth < max_threads {
        /* Create channel to pass the results back */
        let (sender, receiver) = channel();
        let left_cell = RefCell::new(left); // the only way to access the above mutable field
        spawn(proc() {
            // take the ref out of the cell, sort it, and send it back to the parent process
            let sorted_left =  parallel_merge_sort(left_cell.unwrap(), depth + 1, max_threads);
            sender.send(sorted_left);
        });
        right = parallel_merge_sort(right, depth + 1, max_threads);

        left = receiver.recv();
    } else {
        left = parallel_merge_sort(left, depth, max_threads);
        right = parallel_merge_sort(right, depth, max_threads);
    }

    merge(left, right)
}

fn merge<T:Ord+Clone>(left_orig: ~[T], right_orig: ~[T]) -> ~[T] {
    let mut left = left_orig.clone();
    let mut right = right_orig.clone();
    let mut result = slice::from_elem(0, left[0].clone());

    while left.len() > 0 || right.len() > 0 {
        if left.len() > 0 && right.len() > 0 {
            if left[0] < right[0] {
                result.push(left.shift().unwrap());
            }
            else {
                result.push(right.shift().unwrap());
            }
        }
        else if left.len() > 0 {
            result.push(left.shift().unwrap());
        }
        else {
            result.push(right.shift().unwrap());
        }
    }

    return result;
}

fn main() {
    let mut bench = Benchmark::new();
    bench.run(parallel_merge_sort_helper);
}

<|endoftext|>


<commit_before>//! A small rust program that sets all nannou crates within the workspace to the specified version.
//!
//! Does the following:
//!
//! - Find all crates via the cargo workspace toml.
//! - Sets the version number for each of the `nannou*` packages and updates each of their
//!   respective `nannou*` dependencies.
//! - Writes the resulting TOML files.

fn main() {
    // Retrieve the specified version from the CLI args.
    let desired_version_string = std::env::args()
        .nth(1)
        .expect("expected one argument with the desired version, e.g. \"0.42.0\"");
    let desired_version = semver::Version::parse(&desired_version_string)
        .expect("failed to parse the specified version as valid semver, e.g. \"0.42.0\"");

    // Read the packages from the workspace manifest.
    let manifest_dir = env!("CARGO_MANIFEST_DIR");
    let workspace_manifest_dir = std::path::Path::new(manifest_dir)
        .parent()
        .unwrap() // nannou/scripts
        .parent()
        .unwrap(); // nannou
    let workspace_manifest_path = workspace_manifest_dir.join("Cargo.toml");
    let workspace_manifest_string = std::fs::read_to_string(&workspace_manifest_path)
        .expect("failed to read the workspace manifest");
    let workspace_toml = workspace_manifest_string
        .parse::<toml_edit::Document>()
        .expect("failed to parse workspace manifest as toml");
    let workspace_table = workspace_toml
        .as_table()
        .get("workspace")
        .and_then(|item| item.as_table())
        .expect("no table 'workspace'");
    let members_array = workspace_table
        .get("members")
        .and_then(|m| m.as_value())
        .and_then(|v| v.as_array())
        .expect("no array 'members'");
    let package_relative_paths: Vec<_> = members_array.iter().filter_map(|v| v.as_str()).collect();

    // Set the versions and dependency versions where necessary.
    let mut manifest_updates = vec![];
    for relative_path in &package_relative_paths {
        // Read the manifest for each crate into a toml document.
        let dir_path = workspace_manifest_dir.join(&relative_path);
        let manifest_path = dir_path.join("Cargo.toml");
        dbg!(&manifest_path);
        let manifest_string =
            std::fs::read_to_string(&manifest_path).expect("failed to read the manifest");
        let mut manifest_toml = manifest_string
            .parse::<toml_edit::Document>()
            .expect("failed to parse manifest as toml");
        let manifest_table = manifest_toml.as_table_mut();

        // Update the manifest table.
        if is_nannou_member(relative_path) {
            set_package_version(manifest_table, &desired_version);
        }
        if let Some(deps) = manifest_table.entry("dependencies").as_table_mut() {
            update_dependencies_table(deps, &desired_version);
        }
        if let Some(deps) = manifest_table.entry("dev-dependencies").as_table_mut() {
            update_dependencies_table(deps, &desired_version);
        }

        // Retrieve the updated string.
        let toml_string = manifest_toml.to_string_in_original_order();
        manifest_updates.push((manifest_path, toml_string));
    }

    // Only write the files once we've successfully created a new TOML string for each package.
    for (manifest_path, toml_string) in manifest_updates {
        safe_file_save(&manifest_path, toml_string.as_bytes())
            .expect("failed to write the edited manifest");
    }

    println!("Successfully set version to {}!", desired_version);
}

/// Set the version within the package entry of the given manifest table.
fn set_package_version(manifest_table: &mut toml_edit::Table, desired_version: &semver::Version) {
    let package_table = manifest_table
        .entry("package")
        .as_table_mut()
        .expect("failed to retrieve package table");
    let version_value = package_table
        .entry("version")
        .as_value_mut()
        .expect("failed to retrieve value for version key");
    *version_value = format!("{}", desired_version).into();
}

/// Shared between updating the `[dependencies]` and `[dev-dependencies]` tables.
fn update_dependencies_table(table: &mut toml_edit::Table, desired_version: &semver::Version) {
    let nannou_deps: Vec<_> = table
        .iter()
        .map(|(name, _)| name.to_string())
        .filter(|s| is_nannou_member(s))
        .collect();
    for dep in nannou_deps {
        let value = table
            .entry(&dep)
            .as_value_mut()
            .expect("failed to retrieve toml value for dependency");
        let version_value = match *value {
            toml_edit::Value::String(_) => value,
            toml_edit::Value::InlineTable(ref mut inline_table) => {
                inline_table.get_or_insert("version", "")
            }
            ref v => panic!("unexpected dependency value: {:?}", v),
        };
        *version_value = format!("{}", desired_version).into();
    }
}

/// Check if the given crate name is one of the nannou crates whose version requires setting.
fn is_nannou_member(workspace_member_name: &str) -> bool {
    workspace_member_name.contains("nannou")
}

/// Saves the file to a temporary file before removing the original to reduce the chance of losing
/// data in the case that something goes wrong during saving.
pub fn safe_file_save(path: &std::path::Path, content: &[u8]) -> std::io::Result<()> {
    use std::io::Write;
    let temp_path = path.with_extension("tmp");

    // If the temp file exists, remove it.
    if temp_path.exists() {
        std::fs::remove_file(&temp_path)?;
    }

    // Write the temp file.
    let file = std::fs::File::create(&temp_path)?;
    let mut buffered = std::io::BufWriter::new(file);
    buffered.write(content)?;

    // If there's already a file at `path`, remove it.
    if path.exists() {
        std::fs::remove_file(&path)?;
    }

    // Rename the temp file to the original path name.
    std::fs::rename(temp_path, path)?;

    Ok(())
}
<commit_msg>Remove unnecessary dbg print<commit_after>//! A small rust program that sets all nannou crates within the workspace to the specified version.
//!
//! Does the following:
//!
//! - Find all crates via the cargo workspace toml.
//! - Sets the version number for each of the `nannou*` packages and updates each of their
//!   respective `nannou*` dependencies.
//! - Writes the resulting TOML files.

fn main() {
    // Retrieve the specified version from the CLI args.
    let desired_version_string = std::env::args()
        .nth(1)
        .expect("expected one argument with the desired version, e.g. \"0.42.0\"");
    let desired_version = semver::Version::parse(&desired_version_string)
        .expect("failed to parse the specified version as valid semver, e.g. \"0.42.0\"");

    // Read the packages from the workspace manifest.
    let manifest_dir = env!("CARGO_MANIFEST_DIR");
    let workspace_manifest_dir = std::path::Path::new(manifest_dir)
        .parent()
        .unwrap() // nannou/scripts
        .parent()
        .unwrap(); // nannou
    let workspace_manifest_path = workspace_manifest_dir.join("Cargo.toml");
    let workspace_manifest_string = std::fs::read_to_string(&workspace_manifest_path)
        .expect("failed to read the workspace manifest");
    let workspace_toml = workspace_manifest_string
        .parse::<toml_edit::Document>()
        .expect("failed to parse workspace manifest as toml");
    let workspace_table = workspace_toml
        .as_table()
        .get("workspace")
        .and_then(|item| item.as_table())
        .expect("no table 'workspace'");
    let members_array = workspace_table
        .get("members")
        .and_then(|m| m.as_value())
        .and_then(|v| v.as_array())
        .expect("no array 'members'");
    let package_relative_paths: Vec<_> = members_array.iter().filter_map(|v| v.as_str()).collect();

    // Set the versions and dependency versions where necessary.
    let mut manifest_updates = vec![];
    for relative_path in &package_relative_paths {
        // Read the manifest for each crate into a toml document.
        let dir_path = workspace_manifest_dir.join(&relative_path);
        let manifest_path = dir_path.join("Cargo.toml");
        let manifest_string =
            std::fs::read_to_string(&manifest_path).expect("failed to read the manifest");
        let mut manifest_toml = manifest_string
            .parse::<toml_edit::Document>()
            .expect("failed to parse manifest as toml");
        let manifest_table = manifest_toml.as_table_mut();

        // Update the manifest table.
        if is_nannou_member(relative_path) {
            set_package_version(manifest_table, &desired_version);
        }
        if let Some(deps) = manifest_table.entry("dependencies").as_table_mut() {
            update_dependencies_table(deps, &desired_version);
        }
        if let Some(deps) = manifest_table.entry("dev-dependencies").as_table_mut() {
            update_dependencies_table(deps, &desired_version);
        }

        // Retrieve the updated string.
        let toml_string = manifest_toml.to_string_in_original_order();
        manifest_updates.push((manifest_path, toml_string));
    }

    // Only write the files once we've successfully created a new TOML string for each package.
    for (manifest_path, toml_string) in manifest_updates {
        safe_file_save(&manifest_path, toml_string.as_bytes())
            .expect("failed to write the edited manifest");
    }

    println!("Successfully set version to {}!", desired_version);
}

/// Set the version within the package entry of the given manifest table.
fn set_package_version(manifest_table: &mut toml_edit::Table, desired_version: &semver::Version) {
    let package_table = manifest_table
        .entry("package")
        .as_table_mut()
        .expect("failed to retrieve package table");
    let version_value = package_table
        .entry("version")
        .as_value_mut()
        .expect("failed to retrieve value for version key");
    *version_value = format!("{}", desired_version).into();
}

/// Shared between updating the `[dependencies]` and `[dev-dependencies]` tables.
fn update_dependencies_table(table: &mut toml_edit::Table, desired_version: &semver::Version) {
    let nannou_deps: Vec<_> = table
        .iter()
        .map(|(name, _)| name.to_string())
        .filter(|s| is_nannou_member(s))
        .collect();
    for dep in nannou_deps {
        let value = table
            .entry(&dep)
            .as_value_mut()
            .expect("failed to retrieve toml value for dependency");
        let version_value = match *value {
            toml_edit::Value::String(_) => value,
            toml_edit::Value::InlineTable(ref mut inline_table) => {
                inline_table.get_or_insert("version", "")
            }
            ref v => panic!("unexpected dependency value: {:?}", v),
        };
        *version_value = format!("{}", desired_version).into();
    }
}

/// Check if the given crate name is one of the nannou crates whose version requires setting.
fn is_nannou_member(workspace_member_name: &str) -> bool {
    workspace_member_name.contains("nannou")
}

/// Saves the file to a temporary file before removing the original to reduce the chance of losing
/// data in the case that something goes wrong during saving.
pub fn safe_file_save(path: &std::path::Path, content: &[u8]) -> std::io::Result<()> {
    use std::io::Write;
    let temp_path = path.with_extension("tmp");

    // If the temp file exists, remove it.
    if temp_path.exists() {
        std::fs::remove_file(&temp_path)?;
    }

    // Write the temp file.
    let file = std::fs::File::create(&temp_path)?;
    let mut buffered = std::io::BufWriter::new(file);
    buffered.write(content)?;

    // If there's already a file at `path`, remove it.
    if path.exists() {
        std::fs::remove_file(&path)?;
    }

    // Rename the temp file to the original path name.
    std::fs::rename(temp_path, path)?;

    Ok(())
}
<|endoftext|>