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

use cssparser::RGBA;
use dom::bindings::codegen::Bindings::HTMLTableCellElementBinding::HTMLTableCellElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::root::LayoutDom;
use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::element::{Element, RawLayoutElementHelpers};
use dom::htmlelement::HTMLElement;
use dom::htmltablerowelement::HTMLTableRowElement;
use dom::node::Node;
use dom::virtualmethods::VirtualMethods;
use dom_struct::dom_struct;
use html5ever::{LocalName, Prefix};
use style::attr::{AttrValue, LengthOrPercentageOrAuto};

const DEFAULT_COLSPAN: u32 = 1;
const DEFAULT_ROWSPAN: u32 = 1;

#[dom_struct]
pub struct HTMLTableCellElement {
    htmlelement: HTMLElement,
}

impl HTMLTableCellElement {
    pub fn new_inherited(tag_name: LocalName,
                         prefix: Option<Prefix>,
                         document: &Document)
                         -> HTMLTableCellElement {
        HTMLTableCellElement {
            htmlelement: HTMLElement::new_inherited(tag_name, prefix, document),
        }
    }
}

impl HTMLTableCellElementMethods for HTMLTableCellElement {
    // https://html.spec.whatwg.org/multipage/#dom-tdth-colspan
    make_uint_getter!(ColSpan, "colspan", DEFAULT_COLSPAN);

    // https://html.spec.whatwg.org/multipage/#dom-tdth-colspan
    make_uint_setter!(SetColSpan, "colspan", DEFAULT_COLSPAN);

    // https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan
    make_uint_getter!(RowSpan, "rowspan", DEFAULT_ROWSPAN);

    // https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan
    make_uint_setter!(SetRowSpan, "rowspan", DEFAULT_ROWSPAN);

    // https://html.spec.whatwg.org/multipage/#dom-tdth-bgcolor
    make_getter!(BgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage/#dom-tdth-bgcolor
    make_legacy_color_setter!(SetBgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage/#dom-tdth-width
    make_getter!(Width, "width");

    // https://html.spec.whatwg.org/multipage/#dom-tdth-width
    make_nonzero_dimension_setter!(SetWidth, "width");

    // https://html.spec.whatwg.org/multipage/#dom-tdth-cellindex
    fn CellIndex(&self) -> i32 {
        let self_node = self.upcast::<Node>();

        let parent_children = match self_node.GetParentNode() {
            Some(ref parent_node) if parent_node.is::<HTMLTableRowElement>() => {
                parent_node.children()
            },
            _ => return -1,
        };

        parent_children.filter(|c| c.is::<HTMLTableCellElement>())
                       .position(|c| &*c == self_node)
                       .map_or(-1, |p| p as i32)
    }
}

pub trait HTMLTableCellElementLayoutHelpers {
    fn get_background_color(&self) -> Option<RGBA>;
    fn get_colspan(&self) -> Option<u32>;
    fn get_rowspan(&self) -> Option<u32>;
    fn get_width(&self) -> LengthOrPercentageOrAuto;
}

#[allow(unsafe_code)]
impl HTMLTableCellElementLayoutHelpers for LayoutDom<HTMLTableCellElement> {
    fn get_background_color(&self) -> Option<RGBA> {
        unsafe {
            (&*self.upcast::<Element>().unsafe_get())
                .get_attr_for_layout(&ns!(), &local_name!("bgcolor"))
                .and_then(AttrValue::as_color)
                .cloned()
        }
    }

    fn get_colspan(&self) -> Option<u32> {
        unsafe {
            (&*self.upcast::<Element>().unsafe_get())
                .get_attr_for_layout(&ns!(), &local_name!("colspan"))
                .map(AttrValue::as_uint)
        }
    }

    fn get_rowspan(&self) -> Option<u32> {
        unsafe {
            (&*self.upcast::<Element>().unsafe_get())
                .get_attr_for_layout(&ns!(), &local_name!("rowspan"))
                .map(AttrValue::as_uint)
        }
    }

    fn get_width(&self) -> LengthOrPercentageOrAuto {
        unsafe {
            (&*self.upcast::<Element>().unsafe_get())
                .get_attr_for_layout(&ns!(), &local_name!("width"))
                .map(AttrValue::as_dimension)
                .cloned()
                .unwrap_or(LengthOrPercentageOrAuto::Auto)
        }
    }
}

impl VirtualMethods for HTMLTableCellElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
        match *local_name {
            local_name!("colspan") => AttrValue::from_u32(value.into(), DEFAULT_COLSPAN),
            local_name!("rowspan") => AttrValue::from_u32(value.into(), DEFAULT_ROWSPAN),
            local_name!("bgcolor") => AttrValue::from_legacy_color(value.into()),
            local_name!("width") => AttrValue::from_nonzero_dimension(value.into()),
            _ => self.super_type().unwrap().parse_plain_attribute(local_name, value),
        }
    }
}
<commit_msg>Fixup specified colspans and rowspans<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::RGBA;
use dom::bindings::codegen::Bindings::HTMLTableCellElementBinding::HTMLTableCellElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::root::LayoutDom;
use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::element::{Element, RawLayoutElementHelpers};
use dom::htmlelement::HTMLElement;
use dom::htmltablerowelement::HTMLTableRowElement;
use dom::node::Node;
use dom::virtualmethods::VirtualMethods;
use dom_struct::dom_struct;
use html5ever::{LocalName, Prefix};
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
use style::context::QuirksMode;

const DEFAULT_COLSPAN: u32 = 1;
const DEFAULT_ROWSPAN: u32 = 1;

#[dom_struct]
pub struct HTMLTableCellElement {
    htmlelement: HTMLElement,
}

impl HTMLTableCellElement {
    pub fn new_inherited(tag_name: LocalName,
                         prefix: Option<Prefix>,
                         document: &Document)
                         -> HTMLTableCellElement {
        HTMLTableCellElement {
            htmlelement: HTMLElement::new_inherited(tag_name, prefix, document),
        }
    }
}

impl HTMLTableCellElementMethods for HTMLTableCellElement {
    // https://html.spec.whatwg.org/multipage/#dom-tdth-colspan
    make_uint_getter!(ColSpan, "colspan", DEFAULT_COLSPAN);

    // https://html.spec.whatwg.org/multipage/#dom-tdth-colspan
    make_uint_setter!(SetColSpan, "colspan", DEFAULT_COLSPAN);

    // https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan
    make_uint_getter!(RowSpan, "rowspan", DEFAULT_ROWSPAN);

    // https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan
    make_uint_setter!(SetRowSpan, "rowspan", DEFAULT_ROWSPAN);

    // https://html.spec.whatwg.org/multipage/#dom-tdth-bgcolor
    make_getter!(BgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage/#dom-tdth-bgcolor
    make_legacy_color_setter!(SetBgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage/#dom-tdth-width
    make_getter!(Width, "width");

    // https://html.spec.whatwg.org/multipage/#dom-tdth-width
    make_nonzero_dimension_setter!(SetWidth, "width");

    // https://html.spec.whatwg.org/multipage/#dom-tdth-cellindex
    fn CellIndex(&self) -> i32 {
        let self_node = self.upcast::<Node>();

        let parent_children = match self_node.GetParentNode() {
            Some(ref parent_node) if parent_node.is::<HTMLTableRowElement>() => {
                parent_node.children()
            },
            _ => return -1,
        };

        parent_children.filter(|c| c.is::<HTMLTableCellElement>())
                       .position(|c| &*c == self_node)
                       .map_or(-1, |p| p as i32)
    }
}

pub trait HTMLTableCellElementLayoutHelpers {
    fn get_background_color(&self) -> Option<RGBA>;
    fn get_colspan(&self) -> Option<u32>;
    fn get_rowspan(&self) -> Option<u32>;
    fn get_width(&self) -> LengthOrPercentageOrAuto;
}

#[allow(unsafe_code)]
impl HTMLTableCellElementLayoutHelpers for LayoutDom<HTMLTableCellElement> {
    fn get_background_color(&self) -> Option<RGBA> {
        unsafe {
            (&*self.upcast::<Element>().unsafe_get())
                .get_attr_for_layout(&ns!(), &local_name!("bgcolor"))
                .and_then(AttrValue::as_color)
                .cloned()
        }
    }

    fn get_colspan(&self) -> Option<u32> {
        unsafe {
            (&*self.upcast::<Element>().unsafe_get())
                .get_attr_for_layout(&ns!(), &local_name!("colspan"))
                .map(AttrValue::as_uint)
        }
    }

    fn get_rowspan(&self) -> Option<u32> {
        unsafe {
            (&*self.upcast::<Element>().unsafe_get())
                .get_attr_for_layout(&ns!(), &local_name!("rowspan"))
                .map(AttrValue::as_uint)
        }
    }

    fn get_width(&self) -> LengthOrPercentageOrAuto {
        unsafe {
            (&*self.upcast::<Element>().unsafe_get())
                .get_attr_for_layout(&ns!(), &local_name!("width"))
                .map(AttrValue::as_dimension)
                .cloned()
                .unwrap_or(LengthOrPercentageOrAuto::Auto)
        }
    }
}

impl VirtualMethods for HTMLTableCellElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
        match *local_name {
            local_name!("colspan") => {
                let mut attr = AttrValue::from_u32(value.into(), DEFAULT_COLSPAN);
                if let AttrValue::UInt(ref mut s, ref mut val) = attr {
                    if *val == 0 {
                        *val = 1;
                        *s = "1".into();
                    }
                }
                attr
            }
            local_name!("rowspan") => {
                let mut attr = AttrValue::from_u32(value.into(), DEFAULT_ROWSPAN);
                if let AttrValue::UInt(ref mut s, ref mut val) = attr {
                    if *val == 0 {
                        let node = self.upcast::<Node>();
                        let doc = node.owner_doc();
                        // rowspan = 0 is not supported in quirks mode
                        if doc.quirks_mode() != QuirksMode::NoQuirks {
                            *val = 1;
                            *s = "1".into();
                        }
                    }
                }
                attr
            }
            local_name!("bgcolor") => AttrValue::from_legacy_color(value.into()),
            local_name!("width") => AttrValue::from_nonzero_dimension(value.into()),
            _ => self.super_type().unwrap().parse_plain_attribute(local_name, value),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Athena Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate zeus;
extern crate conrod;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate piston;

extern crate winapi;
extern crate ole32;
extern crate uuid;

use conrod::{Background, Button, Color, Colorable, Label, Labelable, Positionable, Sizeable, TextBox, Theme, Ui, Widget};
use conrod::color::{rgb};
use glutin_window::{GlutinWindow};
use opengl_graphics::{GlGraphics, OpenGL};
use opengl_graphics::glyph_cache::GlyphCache;
use piston::event::*;
use piston::window::{WindowSettings, Size};
use std::path::{Path, PathBuf};
use zeus::project::*;

fn main() {
    let opengl = OpenGL::_3_2;
    let window = GlutinWindow::new(
        opengl,
        WindowSettings::new(
            "Athena".to_string(),
            Size { width: 500, height: 200 }
        )
        .exit_on_esc(true)
        .samples(4)
    );
    let event_iter = window.events().ups(180).max_fps(60);
    let mut gl = GlGraphics::new(opengl);

    let font_path = Path::new("./assets/NotoSans/NotoSans-Regular.ttf");
    let theme = Theme::default();
    let glyph_cache = GlyphCache::new(&font_path).unwrap();
    let ui = &mut Ui::new(glyph_cache, theme);

    // UI model variables
    let mut path = String::new();
    let mut status_label = String::new();

    for event in event_iter {
        ui.handle_event(&event);
        if let Some(args) = event.render_args() {
            gl.draw(args.viewport(), |c, gl| {
                // Draw the background
                Background::new().color(rgb(0.082, 0.090, 0.094)).draw(ui, gl);

                // Draw a path textbox
                TextBox::new(&mut path)
                    .xy(-50.0, 50.0)
                    .dimensions(300.0, 30.0)
                    .font_size(14)
                    .react(|_string: &mut String|{})
                    .set(0, ui);

                Button::new()
                    .xy(150.0, 50.0)
                    .dimensions(100.0, 30.0)
                    .label("Browse")
                    .react(|| path = browse_pressed())
                    .set(1, ui);

                if path != "" {
                    Button::new()
                        .xy(-100.0, 0.0)
                        .dimensions(100.0, 30.0)
                        .label("New")
                        .react(|| status_label = new_pressed(&path))
                        .set(2, ui);

                    Button::new()
                        .xy(100.0, 0.0)
                        .dimensions(100.0, 30.0)
                        .label("Open")
                        .react(|| status_label = open_pressed(&path))
                        .set(3, ui);
                }

                Label::new(&status_label)
                    .xy(0.0, -50.0)
                    .font_size(16)
                    .color(rgb(1.0, 1.0, 1.0))
                    .set(4, ui);

                // Draw our UI
                ui.draw(c, gl);
            });
        }
    }
}

fn browse_pressed() -> String {
    unsafe {
        // TODO: Add cleanup code

        check_result(ole32::CoInitializeEx(::std::ptr::null_mut(), 0));

        // Create the dialog
        let file_dialog = {
            let mut file_dialog: *mut winapi::IFileOpenDialog = std::mem::uninitialized();
            let hresult = ole32::CoCreateInstance(
                &uuid::CLSID_FileOpenDialog,
                std::ptr::null_mut(), winapi::CLSCTX_ALL,
                &uuid::IID_IFileOpenDialog,
                std::mem::transmute(&mut file_dialog));

            check_result(hresult);
            &mut *file_dialog
        };

        check_result(file_dialog.SetOptions(winapi::FILEOPENDIALOGOPTIONS::PICKFOLDERS));

        // Show the dialog
        if file_dialog.Show(0 as winapi::HWND) < 0 {
            // Got canceled
            return String::from("")
        }

        // Get the file name from the dialog
        let path = {
            let mut item: *mut winapi::IShellItem = std::mem::uninitialized();
            check_result(file_dialog.GetResult(std::mem::transmute(&mut item)));

            let mut raw_path: *mut winapi::LPWSTR = std::mem::uninitialized();
            check_result((*item).GetDisplayName(winapi::SIGDN::FILESYSPATH, std::mem::transmute(&mut raw_path)));

            // TODO: Convert from LPWSTR to String

            String::from("test")
        };

        path
    }
}

fn new_pressed(path: &str) -> String {
    match ZeusProject::create(PathBuf::from(path)) {
        Ok(_) => String::from(format!("Created new at {}", path)),
        Err(e) => String::from(format!("Error: {}", e))
    }
}

fn open_pressed(path: &str) -> String {
    match ZeusProject::open(PathBuf::from(path)) {
        Ok(p) => String::from(format!("Opened: {}", p.game_name())),
        Err(e) => String::from(format!("Error: {}", e))
    }
}

fn check_result(result: winapi::HRESULT) {
    if result < 0 {
        return panic!("Error in winapi call: {:x}", result);
    }
}
<commit_msg>Add string conversion from folder browser output to text field<commit_after>// Copyright 2015 The Athena Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate zeus;
extern crate conrod;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate piston;

extern crate winapi;
extern crate ole32;
extern crate uuid;

use conrod::{Background, Button, Color, Colorable, Label, Labelable, Positionable, Sizeable, TextBox, Theme, Ui, Widget};
use conrod::color::{rgb};
use glutin_window::{GlutinWindow};
use opengl_graphics::{GlGraphics, OpenGL};
use opengl_graphics::glyph_cache::GlyphCache;
use piston::event::*;
use piston::window::{WindowSettings, Size};
use std::path::{Path, PathBuf};
use zeus::project::*;

fn main() {
    let opengl = OpenGL::_3_2;
    let window = GlutinWindow::new(
        opengl,
        WindowSettings::new(
            "Athena".to_string(),
            Size { width: 500, height: 200 }
        )
        .exit_on_esc(true)
        .samples(4)
    );
    let event_iter = window.events().ups(180).max_fps(60);
    let mut gl = GlGraphics::new(opengl);

    let font_path = Path::new("./assets/NotoSans/NotoSans-Regular.ttf");
    let theme = Theme::default();
    let glyph_cache = GlyphCache::new(&font_path).unwrap();
    let ui = &mut Ui::new(glyph_cache, theme);

    // UI model variables
    let mut path = String::new();
    let mut status_label = String::new();

    for event in event_iter {
        ui.handle_event(&event);
        if let Some(args) = event.render_args() {
            gl.draw(args.viewport(), |c, gl| {
                // Draw the background
                Background::new().color(rgb(0.082, 0.090, 0.094)).draw(ui, gl);

                // Draw a path textbox
                TextBox::new(&mut path)
                    .xy(-50.0, 50.0)
                    .dimensions(300.0, 30.0)
                    .font_size(14)
                    .react(|_string: &mut String|{})
                    .set(0, ui);

                Button::new()
                    .xy(150.0, 50.0)
                    .dimensions(100.0, 30.0)
                    .label("Browse")
                    .react(|| path = browse_pressed())
                    .set(1, ui);

                if path != "" {
                    Button::new()
                        .xy(-100.0, 0.0)
                        .dimensions(100.0, 30.0)
                        .label("New")
                        .react(|| status_label = new_pressed(&path))
                        .set(2, ui);

                    Button::new()
                        .xy(100.0, 0.0)
                        .dimensions(100.0, 30.0)
                        .label("Open")
                        .react(|| status_label = open_pressed(&path))
                        .set(3, ui);
                }

                Label::new(&status_label)
                    .xy(0.0, -50.0)
                    .font_size(16)
                    .color(rgb(1.0, 1.0, 1.0))
                    .set(4, ui);

                // Draw our UI
                ui.draw(c, gl);
            });
        }
    }
}

fn browse_pressed() -> String {
    unsafe {
        // TODO: Add cleanup code

        check_result(ole32::CoInitializeEx(::std::ptr::null_mut(), 0));

        // Create the dialog
        let file_dialog = {
            let mut file_dialog: *mut winapi::IFileOpenDialog = std::mem::uninitialized();
            let hresult = ole32::CoCreateInstance(
                &uuid::CLSID_FileOpenDialog,
                std::ptr::null_mut(), winapi::CLSCTX_ALL,
                &uuid::IID_IFileOpenDialog,
                std::mem::transmute(&mut file_dialog));

            check_result(hresult);
            &mut *file_dialog
        };

        check_result(file_dialog.SetOptions(winapi::FILEOPENDIALOGOPTIONS::PICKFOLDERS));

        // Show the dialog
        if file_dialog.Show(0 as winapi::HWND) < 0 {
            // Got canceled
            return String::from("")
        }

        // Get the file name from the dialog
        let path = {
            let mut item: *mut winapi::IShellItem = std::mem::uninitialized();
            check_result(file_dialog.GetResult(std::mem::transmute(&mut item)));

            let mut raw_path: *mut winapi::LPWSTR = std::mem::uninitialized();
            check_result((*item).GetDisplayName(winapi::SIGDN::FILESYSPATH, std::mem::transmute(&mut raw_path)));

            let os_path: std::ffi::OsString = OsStringFromPtr::from_wide_ptr(std::mem::transmute(raw_path));

            String::from(os_path.to_str().unwrap())
        };

        path
    }
}

fn new_pressed(path: &str) -> String {
    match ZeusProject::create(PathBuf::from(path)) {
        Ok(_) => String::from(format!("Created new at {}", path)),
        Err(e) => String::from(format!("Error: {}", e))
    }
}

fn open_pressed(path: &str) -> String {
    match ZeusProject::open(PathBuf::from(path)) {
        Ok(p) => String::from(format!("Opened: {}", p.game_name())),
        Err(e) => String::from(format!("Error: {}", e))
    }
}

fn check_result(result: winapi::HRESULT) {
    if result < 0 {
        return panic!("Error in winapi call: {:x}", result);
    }
}

pub trait OsStringFromPtr {
    unsafe fn from_wide_ptr(winapi::LPWSTR) -> Self;
}

impl OsStringFromPtr for std::ffi::OsString {
    unsafe fn from_wide_ptr(ptr: winapi::LPWSTR) -> Self {
        use std::ffi::OsString;
        use std::os::windows::ffi::OsStringExt;
        assert!(!ptr.is_null());
        let mut len = 0;
        while *ptr.offset(len) != 0 {
            len += 1
        }
        let slice = std::slice::from_raw_parts(ptr, len as usize);
        OsString::from_wide(slice)
    }
}
<|endoftext|>


<commit_before>extern crate gcc;

fn compile_chipmunk() {
    let input = [
        "chipmunk/src/chipmunk.c",
        "chipmunk/src/cpArbiter.c",
        "chipmunk/src/cpArray.c",
        "chipmunk/src/cpBBTree.c",
        "chipmunk/src/cpBody.c",
        "chipmunk/src/cpCollision.c",
        "chipmunk/src/cpConstraint.c",
        "chipmunk/src/cpDampedRotarySpring.c",
        "chipmunk/src/cpDampedSpring.c",
        "chipmunk/src/cpGearJoint.c",
        "chipmunk/src/cpGrooveJoint.c",
        "chipmunk/src/cpHashSet.c",
        "chipmunk/src/cpHastySpace.c",
        "chipmunk/src/cpMarch.c",
        "chipmunk/src/cpPinJoint.c",
        "chipmunk/src/cpPivotJoint.c",
        "chipmunk/src/cpPolyShape.c",
        "chipmunk/src/cpPolyline.c",
        "chipmunk/src/cpRatchetJoint.c",
        "chipmunk/src/cpRotaryLimitJoint.c",
        "chipmunk/src/cpShape.c",
        "chipmunk/src/cpSimpleMotor.c",
        "chipmunk/src/cpSlideJoint.c",
        "chipmunk/src/cpSpace.c",
        "chipmunk/src/cpSpaceComponent.c",
        "chipmunk/src/cpSpaceDebug.c",
        "chipmunk/src/cpSpaceHash.c",
        "chipmunk/src/cpSpaceQuery.c",
        "chipmunk/src/cpSpaceStep.c",
        "chipmunk/src/cpSpatialIndex.c",
        "chipmunk/src/cpSweep1D.c",
    ];

      let mut conf = gcc::Config::new();

      conf.include("chipmunk/include/");
      conf.flag("-g");
      conf.flag("-std=c99");

      for src in &input {
          conf.file(src);
      }

      conf.compile("libchipmunk.a");
}

fn main() {
    compile_chipmunk();
}
<commit_msg>Compile library with -DNDEBUG for release profile.<commit_after>extern crate gcc;

use std::env;

fn compile_chipmunk() {
    let input = [
        "chipmunk/src/chipmunk.c",
        "chipmunk/src/cpArbiter.c",
        "chipmunk/src/cpArray.c",
        "chipmunk/src/cpBBTree.c",
        "chipmunk/src/cpBody.c",
        "chipmunk/src/cpCollision.c",
        "chipmunk/src/cpConstraint.c",
        "chipmunk/src/cpDampedRotarySpring.c",
        "chipmunk/src/cpDampedSpring.c",
        "chipmunk/src/cpGearJoint.c",
        "chipmunk/src/cpGrooveJoint.c",
        "chipmunk/src/cpHashSet.c",
        "chipmunk/src/cpHastySpace.c",
        "chipmunk/src/cpMarch.c",
        "chipmunk/src/cpPinJoint.c",
        "chipmunk/src/cpPivotJoint.c",
        "chipmunk/src/cpPolyShape.c",
        "chipmunk/src/cpPolyline.c",
        "chipmunk/src/cpRatchetJoint.c",
        "chipmunk/src/cpRotaryLimitJoint.c",
        "chipmunk/src/cpShape.c",
        "chipmunk/src/cpSimpleMotor.c",
        "chipmunk/src/cpSlideJoint.c",
        "chipmunk/src/cpSpace.c",
        "chipmunk/src/cpSpaceComponent.c",
        "chipmunk/src/cpSpaceDebug.c",
        "chipmunk/src/cpSpaceHash.c",
        "chipmunk/src/cpSpaceQuery.c",
        "chipmunk/src/cpSpaceStep.c",
        "chipmunk/src/cpSpatialIndex.c",
        "chipmunk/src/cpSweep1D.c",
    ];

      let mut conf = gcc::Config::new();

      conf.include("chipmunk/include/");
      conf.flag("-g");
      conf.flag("-std=c99");

      if let Ok(profile) = env::var("PROFILE") {
          if "release" == profile {
              conf.flag("-DNDEBUG");
          }
      }

      for src in &input {
          conf.file(src);
      }

      conf.compile("libchipmunk.a");
}

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


<commit_before>use std::env;
use std::path::PathBuf;

fn main() {
    let target = env::var("TARGET").unwrap();
    let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    let mut lib_dir = manifest_dir.clone();
    let mut dll_dir = manifest_dir.clone();
    if target == "x86_64-pc-windows-msvc" {
        lib_dir.push("msvc");
        lib_dir.push("lib");
        lib_dir.push("64");
        dll_dir.push("msvc");
        dll_dir.push("dll");
        dll_dir.push("64");
    }
    else if target == "x86_64-pc-windows-gnu" {
        lib_dir.push("gnu-mingw");
        lib_dir.push("lib");
        lib_dir.push("64");
        dll_dir.push("gnu-mingw");
        dll_dir.push("dll");
        dll_dir.push("64");
    }
    else if target == "i686-pc-windows-msvc" {
        lib_dir.push("msvc");
        lib_dir.push("lib");
        lib_dir.push("32");
        dll_dir.push("msvc");
        dll_dir.push("dll");
        dll_dir.push("32");
    }
    else if target == "i686-pc-windows-gnu" {
        lib_dir.push("gnu-mingw");
        lib_dir.push("lib");
        lib_dir.push("32");
        dll_dir.push("gnu-mingw");
        dll_dir.push("dll");
        dll_dir.push("32");
    }
    if target.contains("pc-windows") {
        println!("cargo:rustc-link-search=static={}", lib_dir.display());
        for entry in std::fs::read_dir(dll_dir).expect("Can't read DLL dir")  {
            let entry_path = entry.expect("Invalid fs entry").path();
            let file_name_result = entry_path.file_name();
            let mut new_file_path = manifest_dir.clone();
            if let Some(file_name) = file_name_result {
                new_file_path.push(file_name.to_str().unwrap());
                std::fs::copy(&entry_path, new_file_path.as_path()).expect("Can't copy from DLL dir");
            }
        }
    }
}
<commit_msg>Update lib search to search for all lib types.<commit_after>use std::env;
use std::path::PathBuf;

fn main() {
    let target = env::var("TARGET").unwrap();
    let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    let mut lib_dir = manifest_dir.clone();
    let mut dll_dir = manifest_dir.clone();
    if target == "x86_64-pc-windows-msvc" {
        lib_dir.push("msvc");
        lib_dir.push("lib");
        lib_dir.push("64");
        dll_dir.push("msvc");
        dll_dir.push("dll");
        dll_dir.push("64");
    }
    else if target == "x86_64-pc-windows-gnu" {
        lib_dir.push("gnu-mingw");
        lib_dir.push("lib");
        lib_dir.push("64");
        dll_dir.push("gnu-mingw");
        dll_dir.push("dll");
        dll_dir.push("64");
    }
    else if target == "i686-pc-windows-msvc" {
        lib_dir.push("msvc");
        lib_dir.push("lib");
        lib_dir.push("32");
        dll_dir.push("msvc");
        dll_dir.push("dll");
        dll_dir.push("32");
    }
    else if target == "i686-pc-windows-gnu" {
        lib_dir.push("gnu-mingw");
        lib_dir.push("lib");
        lib_dir.push("32");
        dll_dir.push("gnu-mingw");
        dll_dir.push("dll");
        dll_dir.push("32");
    }
    if target.contains("pc-windows") {
        println!("cargo:rustc-link-search=all={}", lib_dir.display());
        for entry in std::fs::read_dir(dll_dir).expect("Can't read DLL dir")  {
            let entry_path = entry.expect("Invalid fs entry").path();
            let file_name_result = entry_path.file_name();
            let mut new_file_path = manifest_dir.clone();
            if let Some(file_name) = file_name_result {
                new_file_path.push(file_name.to_str().unwrap());
                std::fs::copy(&entry_path, new_file_path.as_path()).expect("Can't copy from DLL dir");
            }
        }
    }
}
<|endoftext|>


<commit_before>use cairo::Rectangle;
use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::allowed_url::Fragment;
use crate::aspect_ratio::*;
use crate::bbox::BoundingBox;
use crate::dpi::Dpi;
use crate::drawing_ctx::{ClipMode, DrawingCtx, ViewParams};
use crate::error::{AcquireError, AttributeResultExt, RenderingError};
use crate::float_eq_cairo::ApproxEqCairo;
use crate::length::*;
use crate::node::*;
use crate::parsers::{Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_bag::PropertyBag;
use crate::property_defs::Overflow;
use crate::rect::RectangleExt;
use crate::style::StyleType;
use crate::viewbox::*;

#[derive(Default)]
pub struct Group();

impl NodeTrait for Group {
    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            node.draw_children(cascaded, dc, clipping)
        })
    }
}

/// A no-op node that does not render anything
///
/// Sometimes we just need a node that can contain children, but doesn't
/// render itself or its children.  This is just that kind of node.
#[derive(Default)]
pub struct NonRendering;

impl NodeTrait for NonRendering {
    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }
}

#[derive(Default)]
pub struct Switch();

impl NodeTrait for Switch {
    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            if let Some(child) = node
                .children()
                .filter(|c| c.borrow().get_type() != NodeType::Chars)
                .find(|c| c.borrow().get_cond())
            {
                dc.draw_node_from_stack(&CascadedValues::new(cascaded, &child), &child, clipping)
            } else {
                Ok(dc.empty_bbox())
            }
        })
    }
}

/// Intrinsic dimensions of an SVG document fragment
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct IntrinsicDimensions {
    pub width: Option<LengthHorizontal>,
    pub height: Option<LengthVertical>,
    pub vbox: Option<ViewBox>,
}

#[derive(Default)]
pub struct Svg {
    preserve_aspect_ratio: AspectRatio,
    x: Option<LengthHorizontal>,
    y: Option<LengthVertical>,
    w: Option<LengthHorizontal>,
    h: Option<LengthVertical>,
    vbox: Option<ViewBox>,
    content_style_type: Option<StyleType>,
}

impl Svg {
    pub fn get_size(&self, values: &ComputedValues, dpi: Dpi) -> Option<(i32, i32)> {
        let (_, _, w, h) = self.get_unnormalized_viewport();

        match (w, h, self.vbox) {
            (w, h, Some(vbox)) => {
                let params = ViewParams::new(dpi.x(), dpi.y(), vbox.width, vbox.height);

                Some((
                    w.normalize(values, &params).round() as i32,
                    h.normalize(values, &params).round() as i32,
                ))
            }

            (w, h, None) if w.unit() != LengthUnit::Percent && h.unit() != LengthUnit::Percent => {
                let params = ViewParams::new(dpi.x(), dpi.y(), 0.0, 0.0);

                Some((
                    w.normalize(values, &params).round() as i32,
                    h.normalize(values, &params).round() as i32,
                ))
            }
            (_, _, _) => None,
        }
    }

    pub fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
        IntrinsicDimensions {
            width: self.w,
            height: self.h,
            vbox: self.vbox,
        }
    }

    // returns (x, y, w, h)
    fn get_unnormalized_viewport(
        &self,
    ) -> (
        LengthHorizontal,
        LengthVertical,
        LengthHorizontal,
        LengthVertical,
    ) {
        // these defaults are per the spec
        let x = self
            .x
            .unwrap_or_else(|| LengthHorizontal::parse_str("0").unwrap());
        let y = self
            .y
            .unwrap_or_else(|| LengthVertical::parse_str("0").unwrap());
        let w = self
            .w
            .unwrap_or_else(|| LengthHorizontal::parse_str("100%").unwrap());
        let h = self
            .h
            .unwrap_or_else(|| LengthVertical::parse_str("100%").unwrap());

        (x, y, w, h)
    }

    fn get_viewport(&self, values: &ComputedValues, params: &ViewParams) -> Rectangle {
        let (x, y, w, h) = self.get_unnormalized_viewport();

        Rectangle::new(
            x.normalize(values, &params),
            y.normalize(values, &params),
            w.normalize(values, &params),
            h.normalize(values, &params),
        )
    }

    pub fn content_style_type(&self) -> StyleType {
        self.content_style_type.unwrap_or(StyleType::TextCss)
    }
}

impl NodeTrait for Svg {
    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        // x & y attributes have no effect on outermost svg
        // http://www.w3.org/TR/SVG/struct.html#SVGElement
        let is_inner_svg = parent.is_some();

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "preserveAspectRatio") => {
                    self.preserve_aspect_ratio = attr.parse(value)?
                }
                expanded_name!(svg "x") if is_inner_svg => self.x = Some(attr.parse(value)?),
                expanded_name!(svg "y") if is_inner_svg => self.y = Some(attr.parse(value)?),
                expanded_name!(svg "width") => {
                    self.w =
                        Some(attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?)
                }
                expanded_name!(svg "height") => {
                    self.h =
                        Some(attr.parse_and_validate(value, LengthVertical::check_nonnegative)?)
                }
                expanded_name!(svg "viewBox") => self.vbox = attr.parse(value).map(Some)?,
                expanded_name!(svg "contentStyleType") => {
                    self.content_style_type = Some(attr.parse(value)?)
                }
                _ => (),
            }
        }

        Ok(())
    }

    fn overflow_hidden(&self) -> bool {
        true
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        let params = draw_ctx.get_view_params();

        let has_parent = node.parent().is_some();

        let clip_mode = if !values.is_overflow() && has_parent {
            Some(ClipMode::ClipToViewport)
        } else {
            None
        };

        let svg_viewport = self.get_viewport(values, &params);

        let is_measuring_toplevel_svg = !has_parent && draw_ctx.is_measuring();

        let (viewport, vbox) = if is_measuring_toplevel_svg {
            // We are obtaining the toplevel SVG's geometry.  This means, don't care about the
            // DrawingCtx's viewport, just use the SVG's intrinsic dimensions and see how far
            // it wants to extend.
            (svg_viewport, self.vbox)
        } else if has_parent {
            (svg_viewport, self.vbox)
        } else {
            (
                // The client's viewport overrides the toplevel's x/y/w/h viewport
                draw_ctx.toplevel_viewport(),
                // Use our viewBox if available, or try to derive one from
                // the intrinsic dimensions.
                self.vbox.or_else(|| {
                    Some(ViewBox {
                        x: 0.0,
                        y: 0.0,
                        width: svg_viewport.width,
                        height: svg_viewport.height,
                    })
                }),
            )
        };

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            let _params =
                dc.push_new_viewport(vbox, &viewport, self.preserve_aspect_ratio, clip_mode);

            node.draw_children(cascaded, dc, clipping)
        })
    }
}

#[derive(Default)]
pub struct Use {
    link: Option<Fragment>,
    x: LengthHorizontal,
    y: LengthVertical,
    w: Option<LengthHorizontal>,
    h: Option<LengthVertical>,
}

impl NodeTrait for Use {
    fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(xlink "href") => {
                    self.link = Some(Fragment::parse(value).attribute(attr)?)
                }
                expanded_name!(svg "x") => self.x = attr.parse(value)?,
                expanded_name!(svg "y") => self.y = attr.parse(value)?,
                expanded_name!(svg "width") => {
                    self.w = attr
                        .parse_and_validate(value, LengthHorizontal::check_nonnegative)
                        .map(Some)?
                }
                expanded_name!(svg "height") => {
                    self.h = attr
                        .parse_and_validate(value, LengthVertical::check_nonnegative)
                        .map(Some)?
                }
                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        if self.link.is_none() {
            return Ok(draw_ctx.empty_bbox());
        }

        let link = self.link.as_ref().unwrap();

        // <use> is an element that is used directly, unlike
        // <pattern>, which is used through a fill="url(#...)"
        // reference.  However, <use> will always reference another
        // element, potentially itself or an ancestor of itself (or
        // another <use> which references the first one, etc.).  So,
        // we acquire the <use> element itself so that circular
        // references can be caught.
        let _self_acquired = draw_ctx.acquire_node_ref(node).map_err(|e| {
            if let AcquireError::CircularReference(_) = e {
                rsvg_log!("circular reference in element {}", node);
                RenderingError::CircularReference
            } else {
                unreachable!();
            }
        })?;

        let acquired = match draw_ctx.acquire_node(link, &[]) {
            Ok(acquired) => acquired,

            Err(AcquireError::CircularReference(node)) => {
                rsvg_log!("circular reference in element {}", node);
                return Err(RenderingError::CircularReference);
            }

            Err(AcquireError::MaxReferencesExceeded) => {
                return Err(RenderingError::InstancingLimit);
            }

            Err(AcquireError::InvalidLinkType(_)) => unreachable!(),

            Err(AcquireError::LinkNotFound(fragment)) => {
                rsvg_log!("element {} references nonexistent \"{}\"", node, fragment);
                return Ok(draw_ctx.empty_bbox());
            }
        };

        let child = acquired.get();

        let params = draw_ctx.get_view_params();

        let nx = self.x.normalize(values, &params);
        let ny = self.y.normalize(values, &params);

        // If attributes ‘width’ and/or ‘height’ are not specified,
        // [...] use values of '100%' for these attributes.
        // From https://www.w3.org/TR/SVG/struct.html#UseElement in
        // "If the ‘use’ element references a ‘symbol’ element"

        let nw = self
            .w
            .unwrap_or_else(|| LengthHorizontal::parse_str("100%").unwrap())
            .normalize(values, &params);
        let nh = self
            .h
            .unwrap_or_else(|| LengthVertical::parse_str("100%").unwrap())
            .normalize(values, &params);

        // width or height set to 0 disables rendering of the element
        // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
        if nw.approx_eq_cairo(0.0) || nh.approx_eq_cairo(0.0) {
            return Ok(draw_ctx.empty_bbox());
        }

        let viewport = Rectangle::new(nx, ny, nw, nh);

        if child.borrow().get_type() != NodeType::Symbol {
            let cr = draw_ctx.get_cairo_context();
            cr.translate(viewport.x, viewport.y);

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                dc.draw_node_from_stack(
                    &CascadedValues::new_from_values(&child, values),
                    &child,
                    clipping,
                )
            })
        } else {
            let node_data = child.borrow();
            let symbol = node_data.get_impl::<Symbol>();

            let clip_mode = if !values.is_overflow()
                || (values.overflow == Overflow::Visible && child.borrow().is_overflow())
            {
                Some(ClipMode::ClipToVbox)
            } else {
                None
            };

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                let _params = dc.push_new_viewport(
                    symbol.vbox,
                    &viewport,
                    symbol.preserve_aspect_ratio,
                    clip_mode,
                );

                child.draw_children(
                    &CascadedValues::new_from_values(&child, values),
                    dc,
                    clipping,
                )
            })
        }
    }
}

#[derive(Default)]
pub struct Symbol {
    preserve_aspect_ratio: AspectRatio,
    vbox: Option<ViewBox>,
}

impl NodeTrait for Symbol {
    fn set_atts(&mut self, _parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "preserveAspectRatio") => {
                    self.preserve_aspect_ratio = attr.parse(value)?
                }
                expanded_name!(svg "viewBox") => self.vbox = attr.parse(value).map(Some)?,
                _ => (),
            }
        }

        Ok(())
    }

    fn overflow_hidden(&self) -> bool {
        true
    }
}
<commit_msg>Remove content_style_type() after all<commit_after>use cairo::Rectangle;
use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::allowed_url::Fragment;
use crate::aspect_ratio::*;
use crate::bbox::BoundingBox;
use crate::dpi::Dpi;
use crate::drawing_ctx::{ClipMode, DrawingCtx, ViewParams};
use crate::error::{AcquireError, AttributeResultExt, RenderingError};
use crate::float_eq_cairo::ApproxEqCairo;
use crate::length::*;
use crate::node::*;
use crate::parsers::{Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_bag::PropertyBag;
use crate::property_defs::Overflow;
use crate::rect::RectangleExt;
use crate::viewbox::*;

#[derive(Default)]
pub struct Group();

impl NodeTrait for Group {
    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            node.draw_children(cascaded, dc, clipping)
        })
    }
}

/// A no-op node that does not render anything
///
/// Sometimes we just need a node that can contain children, but doesn't
/// render itself or its children.  This is just that kind of node.
#[derive(Default)]
pub struct NonRendering;

impl NodeTrait for NonRendering {
    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }
}

#[derive(Default)]
pub struct Switch();

impl NodeTrait for Switch {
    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            if let Some(child) = node
                .children()
                .filter(|c| c.borrow().get_type() != NodeType::Chars)
                .find(|c| c.borrow().get_cond())
            {
                dc.draw_node_from_stack(&CascadedValues::new(cascaded, &child), &child, clipping)
            } else {
                Ok(dc.empty_bbox())
            }
        })
    }
}

/// Intrinsic dimensions of an SVG document fragment
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct IntrinsicDimensions {
    pub width: Option<LengthHorizontal>,
    pub height: Option<LengthVertical>,
    pub vbox: Option<ViewBox>,
}

#[derive(Default)]
pub struct Svg {
    preserve_aspect_ratio: AspectRatio,
    x: Option<LengthHorizontal>,
    y: Option<LengthVertical>,
    w: Option<LengthHorizontal>,
    h: Option<LengthVertical>,
    vbox: Option<ViewBox>,
}

impl Svg {
    pub fn get_size(&self, values: &ComputedValues, dpi: Dpi) -> Option<(i32, i32)> {
        let (_, _, w, h) = self.get_unnormalized_viewport();

        match (w, h, self.vbox) {
            (w, h, Some(vbox)) => {
                let params = ViewParams::new(dpi.x(), dpi.y(), vbox.width, vbox.height);

                Some((
                    w.normalize(values, &params).round() as i32,
                    h.normalize(values, &params).round() as i32,
                ))
            }

            (w, h, None) if w.unit() != LengthUnit::Percent && h.unit() != LengthUnit::Percent => {
                let params = ViewParams::new(dpi.x(), dpi.y(), 0.0, 0.0);

                Some((
                    w.normalize(values, &params).round() as i32,
                    h.normalize(values, &params).round() as i32,
                ))
            }
            (_, _, _) => None,
        }
    }

    pub fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
        IntrinsicDimensions {
            width: self.w,
            height: self.h,
            vbox: self.vbox,
        }
    }

    // returns (x, y, w, h)
    fn get_unnormalized_viewport(
        &self,
    ) -> (
        LengthHorizontal,
        LengthVertical,
        LengthHorizontal,
        LengthVertical,
    ) {
        // these defaults are per the spec
        let x = self
            .x
            .unwrap_or_else(|| LengthHorizontal::parse_str("0").unwrap());
        let y = self
            .y
            .unwrap_or_else(|| LengthVertical::parse_str("0").unwrap());
        let w = self
            .w
            .unwrap_or_else(|| LengthHorizontal::parse_str("100%").unwrap());
        let h = self
            .h
            .unwrap_or_else(|| LengthVertical::parse_str("100%").unwrap());

        (x, y, w, h)
    }

    fn get_viewport(&self, values: &ComputedValues, params: &ViewParams) -> Rectangle {
        let (x, y, w, h) = self.get_unnormalized_viewport();

        Rectangle::new(
            x.normalize(values, &params),
            y.normalize(values, &params),
            w.normalize(values, &params),
            h.normalize(values, &params),
        )
    }
}

impl NodeTrait for Svg {
    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        // x & y attributes have no effect on outermost svg
        // http://www.w3.org/TR/SVG/struct.html#SVGElement
        let is_inner_svg = parent.is_some();

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "preserveAspectRatio") => {
                    self.preserve_aspect_ratio = attr.parse(value)?
                }
                expanded_name!(svg "x") if is_inner_svg => self.x = Some(attr.parse(value)?),
                expanded_name!(svg "y") if is_inner_svg => self.y = Some(attr.parse(value)?),
                expanded_name!(svg "width") => {
                    self.w =
                        Some(attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?)
                }
                expanded_name!(svg "height") => {
                    self.h =
                        Some(attr.parse_and_validate(value, LengthVertical::check_nonnegative)?)
                }
                expanded_name!(svg "viewBox") => self.vbox = attr.parse(value).map(Some)?,
                _ => (),
            }
        }

        Ok(())
    }

    fn overflow_hidden(&self) -> bool {
        true
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        let params = draw_ctx.get_view_params();

        let has_parent = node.parent().is_some();

        let clip_mode = if !values.is_overflow() && has_parent {
            Some(ClipMode::ClipToViewport)
        } else {
            None
        };

        let svg_viewport = self.get_viewport(values, &params);

        let is_measuring_toplevel_svg = !has_parent && draw_ctx.is_measuring();

        let (viewport, vbox) = if is_measuring_toplevel_svg {
            // We are obtaining the toplevel SVG's geometry.  This means, don't care about the
            // DrawingCtx's viewport, just use the SVG's intrinsic dimensions and see how far
            // it wants to extend.
            (svg_viewport, self.vbox)
        } else if has_parent {
            (svg_viewport, self.vbox)
        } else {
            (
                // The client's viewport overrides the toplevel's x/y/w/h viewport
                draw_ctx.toplevel_viewport(),
                // Use our viewBox if available, or try to derive one from
                // the intrinsic dimensions.
                self.vbox.or_else(|| {
                    Some(ViewBox {
                        x: 0.0,
                        y: 0.0,
                        width: svg_viewport.width,
                        height: svg_viewport.height,
                    })
                }),
            )
        };

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            let _params =
                dc.push_new_viewport(vbox, &viewport, self.preserve_aspect_ratio, clip_mode);

            node.draw_children(cascaded, dc, clipping)
        })
    }
}

#[derive(Default)]
pub struct Use {
    link: Option<Fragment>,
    x: LengthHorizontal,
    y: LengthVertical,
    w: Option<LengthHorizontal>,
    h: Option<LengthVertical>,
}

impl NodeTrait for Use {
    fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(xlink "href") => {
                    self.link = Some(Fragment::parse(value).attribute(attr)?)
                }
                expanded_name!(svg "x") => self.x = attr.parse(value)?,
                expanded_name!(svg "y") => self.y = attr.parse(value)?,
                expanded_name!(svg "width") => {
                    self.w = attr
                        .parse_and_validate(value, LengthHorizontal::check_nonnegative)
                        .map(Some)?
                }
                expanded_name!(svg "height") => {
                    self.h = attr
                        .parse_and_validate(value, LengthVertical::check_nonnegative)
                        .map(Some)?
                }
                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        if self.link.is_none() {
            return Ok(draw_ctx.empty_bbox());
        }

        let link = self.link.as_ref().unwrap();

        // <use> is an element that is used directly, unlike
        // <pattern>, which is used through a fill="url(#...)"
        // reference.  However, <use> will always reference another
        // element, potentially itself or an ancestor of itself (or
        // another <use> which references the first one, etc.).  So,
        // we acquire the <use> element itself so that circular
        // references can be caught.
        let _self_acquired = draw_ctx.acquire_node_ref(node).map_err(|e| {
            if let AcquireError::CircularReference(_) = e {
                rsvg_log!("circular reference in element {}", node);
                RenderingError::CircularReference
            } else {
                unreachable!();
            }
        })?;

        let acquired = match draw_ctx.acquire_node(link, &[]) {
            Ok(acquired) => acquired,

            Err(AcquireError::CircularReference(node)) => {
                rsvg_log!("circular reference in element {}", node);
                return Err(RenderingError::CircularReference);
            }

            Err(AcquireError::MaxReferencesExceeded) => {
                return Err(RenderingError::InstancingLimit);
            }

            Err(AcquireError::InvalidLinkType(_)) => unreachable!(),

            Err(AcquireError::LinkNotFound(fragment)) => {
                rsvg_log!("element {} references nonexistent \"{}\"", node, fragment);
                return Ok(draw_ctx.empty_bbox());
            }
        };

        let child = acquired.get();

        let params = draw_ctx.get_view_params();

        let nx = self.x.normalize(values, &params);
        let ny = self.y.normalize(values, &params);

        // If attributes ‘width’ and/or ‘height’ are not specified,
        // [...] use values of '100%' for these attributes.
        // From https://www.w3.org/TR/SVG/struct.html#UseElement in
        // "If the ‘use’ element references a ‘symbol’ element"

        let nw = self
            .w
            .unwrap_or_else(|| LengthHorizontal::parse_str("100%").unwrap())
            .normalize(values, &params);
        let nh = self
            .h
            .unwrap_or_else(|| LengthVertical::parse_str("100%").unwrap())
            .normalize(values, &params);

        // width or height set to 0 disables rendering of the element
        // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
        if nw.approx_eq_cairo(0.0) || nh.approx_eq_cairo(0.0) {
            return Ok(draw_ctx.empty_bbox());
        }

        let viewport = Rectangle::new(nx, ny, nw, nh);

        if child.borrow().get_type() != NodeType::Symbol {
            let cr = draw_ctx.get_cairo_context();
            cr.translate(viewport.x, viewport.y);

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                dc.draw_node_from_stack(
                    &CascadedValues::new_from_values(&child, values),
                    &child,
                    clipping,
                )
            })
        } else {
            let node_data = child.borrow();
            let symbol = node_data.get_impl::<Symbol>();

            let clip_mode = if !values.is_overflow()
                || (values.overflow == Overflow::Visible && child.borrow().is_overflow())
            {
                Some(ClipMode::ClipToVbox)
            } else {
                None
            };

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                let _params = dc.push_new_viewport(
                    symbol.vbox,
                    &viewport,
                    symbol.preserve_aspect_ratio,
                    clip_mode,
                );

                child.draw_children(
                    &CascadedValues::new_from_values(&child, values),
                    dc,
                    clipping,
                )
            })
        }
    }
}

#[derive(Default)]
pub struct Symbol {
    preserve_aspect_ratio: AspectRatio,
    vbox: Option<ViewBox>,
}

impl NodeTrait for Symbol {
    fn set_atts(&mut self, _parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "preserveAspectRatio") => {
                    self.preserve_aspect_ratio = attr.parse(value)?
                }
                expanded_name!(svg "viewBox") => self.vbox = attr.parse(value).map(Some)?,
                _ => (),
            }
        }

        Ok(())
    }

    fn overflow_hidden(&self) -> bool {
        true
    }
}
<|endoftext|>


<commit_before>use std::ops::RangeInclusive;

use hir::db::HirDatabase;
use ra_syntax::{
    algo::replace_children,
    ast::{self, edit::IndentLevel, make},
    AstNode,
    SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE},
};

use crate::{
    assist_ctx::{Assist, AssistCtx},
    AssistId,
};

// Assist: convert_to_guarded_return
//
// Replace a large conditional with a guarded return.
//
// ```
// fn main() {
//     <|>if cond {
//         foo();
//         bar();
//     }
// }
// ```
// ->
// ```
// fn main() {
//     if !cond {
//         return;
//     }
//     foo();
//     bar();
// }
// ```
pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
    let cond = if_expr.condition()?;
    let pat = &cond.pat();
    let expr = cond.expr()?;
    let then_block = if_expr.then_branch()?.block()?;
    if if_expr.else_branch().is_some() {
        return None;
    }

    let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::Block::cast)?;

    if parent_block.expr()? != if_expr.clone().into() {
        return None;
    }

    // check for early return and continue
    let first_in_then_block = then_block.syntax().first_child()?;
    if ast::ReturnExpr::can_cast(first_in_then_block.kind())
        || ast::ContinueExpr::can_cast(first_in_then_block.kind())
        || first_in_then_block
            .children()
            .any(|x| ast::ReturnExpr::can_cast(x.kind()) || ast::ContinueExpr::can_cast(x.kind()))
    {
        return None;
    }

    let parent_container = parent_block.syntax().parent()?.parent()?;

    let early_expression = match parent_container.kind() {
        WHILE_EXPR | LOOP_EXPR => Some("continue"),
        FN_DEF => Some("return"),
        _ => None,
    }?;

    if then_block.syntax().first_child_or_token().map(|t| t.kind() == L_CURLY).is_none() {
        return None;
    }

    then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?;
    let cursor_position = ctx.frange.range.start();

    ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| {
        let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
        let new_block = match pat {
            None => {
                // If.
                let early_expression = &(early_expression.to_owned() + ";");
                let new_if_expr =
                    if_indent_level.increase_indent(make::if_expression(&expr, early_expression));
                let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
                let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
                let end_of_then =
                    if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
                        end_of_then.prev_sibling_or_token().unwrap()
                    } else {
                        end_of_then
                    };
                let mut new_if_and_then_statements =
                    new_if_expr.syntax().children_with_tokens().chain(
                        then_block_items
                            .syntax()
                            .children_with_tokens()
                            .skip(1)
                            .take_while(|i| *i != end_of_then),
                    );
                replace_children(
                    &parent_block.syntax(),
                    RangeInclusive::new(
                        if_expr.clone().syntax().clone().into(),
                        if_expr.syntax().clone().into(),
                    ),
                    &mut new_if_and_then_statements,
                )
            }
            _ => {
                // If-let.
                let new_match_expr =
                    if_indent_level.increase_indent(make::let_match_early(expr, early_expression));
                let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
                let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
                let end_of_then =
                    if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
                        end_of_then.prev_sibling_or_token().unwrap()
                    } else {
                        end_of_then
                    };
                let mut then_statements = new_match_expr.syntax().children_with_tokens().chain(
                    then_block_items
                        .syntax()
                        .children_with_tokens()
                        .skip(1)
                        .take_while(|i| *i != end_of_then),
                );
                let new_block = replace_children(
                    &parent_block.syntax(),
                    RangeInclusive::new(
                        if_expr.clone().syntax().clone().into(),
                        if_expr.syntax().clone().into(),
                    ),
                    &mut then_statements,
                );
                new_block
            }
        };
        edit.target(if_expr.syntax().text_range());
        edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap());
        edit.set_cursor(cursor_position);
    })
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::helpers::{check_assist, check_assist_not_applicable};

    #[test]
    fn convert_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                bar();
                if<|> true {
                    foo();

                    //comment
                    bar();
                }
            }
            "#,
            r#"
            fn main() {
                bar();
                if<|> !true {
                    return;
                }
                foo();

                //comment
                bar();
            }
            "#,
        );
    }

    #[test]
    fn convert_let_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main(n: Option<String>) {
                bar();
                if<|> let Some(n) = n {
                    foo(n);

                    //comment
                    bar();
                }
            }
            "#,
            r#"
            fn main(n: Option<String>) {
                bar();
                le<|>t n = match n {
                    Some(it) => it,
                    None => return,
                };
                foo(n);

                //comment
                bar();
            }
            "#,
        );
    }

    #[test]
    fn convert_inside_while() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                while true {
                    if<|> true {
                        foo();
                        bar();
                    }
                }
            }
            "#,
            r#"
            fn main() {
                while true {
                    if<|> !true {
                        continue;
                    }
                    foo();
                    bar();
                }
            }
            "#,
        );
    }

    #[test]
    fn convert_let_inside_while() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                while true {
                    if<|> let Some(n) = n {
                        foo(n);
                        bar();
                    }
                }
            }
            "#,
            r#"
            fn main() {
                while true {
                    le<|>t n = match n {
                        Some(it) => it,
                        None => continue,
                    };
                    foo(n);
                    bar();
                }
            }
            "#,
        );
    }

    #[test]
    fn convert_inside_loop() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                loop {
                    if<|> true {
                        foo();
                        bar();
                    }
                }
            }
            "#,
            r#"
            fn main() {
                loop {
                    if<|> !true {
                        continue;
                    }
                    foo();
                    bar();
                }
            }
            "#,
        );
    }

    #[test]
    fn convert_let_inside_loop() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                loop {
                    if<|> let Some(n) = n {
                        foo(n);
                        bar();
                    }
                }
            }
            "#,
            r#"
            fn main() {
                loop {
                    le<|>t n = match n {
                        Some(it) => it,
                        None => continue,
                    };
                    foo(n);
                    bar();
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_already_converted_if() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if<|> true {
                    return;
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_already_converted_loop() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                loop {
                    if<|> true {
                        continue;
                    }
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_return() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if<|> true {
                    return
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_else_branch() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if<|> true {
                    foo();
                } else {
                    bar()
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_statements_aftert_if() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if<|> true {
                    foo();
                }
                bar();
            }
            "#,
        );
    }

    #[test]
    fn ignore_statements_inside_if() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if false {
                    if<|> true {
                        foo();
                    }
                }
            }
            "#,
        );
    }
}
<commit_msg>Remove variable pat.<commit_after>use std::ops::RangeInclusive;

use hir::db::HirDatabase;
use ra_syntax::{
    algo::replace_children,
    ast::{self, edit::IndentLevel, make},
    AstNode,
    SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE},
};

use crate::{
    assist_ctx::{Assist, AssistCtx},
    AssistId,
};

// Assist: convert_to_guarded_return
//
// Replace a large conditional with a guarded return.
//
// ```
// fn main() {
//     <|>if cond {
//         foo();
//         bar();
//     }
// }
// ```
// ->
// ```
// fn main() {
//     if !cond {
//         return;
//     }
//     foo();
//     bar();
// }
// ```
pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
    let cond = if_expr.condition()?;
    let expr = cond.expr()?;
    let then_block = if_expr.then_branch()?.block()?;
    if if_expr.else_branch().is_some() {
        return None;
    }

    let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::Block::cast)?;

    if parent_block.expr()? != if_expr.clone().into() {
        return None;
    }

    // check for early return and continue
    let first_in_then_block = then_block.syntax().first_child()?;
    if ast::ReturnExpr::can_cast(first_in_then_block.kind())
        || ast::ContinueExpr::can_cast(first_in_then_block.kind())
        || first_in_then_block
            .children()
            .any(|x| ast::ReturnExpr::can_cast(x.kind()) || ast::ContinueExpr::can_cast(x.kind()))
    {
        return None;
    }

    let parent_container = parent_block.syntax().parent()?.parent()?;

    let early_expression = match parent_container.kind() {
        WHILE_EXPR | LOOP_EXPR => Some("continue"),
        FN_DEF => Some("return"),
        _ => None,
    }?;

    if then_block.syntax().first_child_or_token().map(|t| t.kind() == L_CURLY).is_none() {
        return None;
    }

    then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?;
    let cursor_position = ctx.frange.range.start();

    ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| {
        let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
        let new_block = match cond.pat() {
            None => {
                // If.
                let early_expression = &(early_expression.to_owned() + ";");
                let new_if_expr =
                    if_indent_level.increase_indent(make::if_expression(&expr, early_expression));
                let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
                let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
                let end_of_then =
                    if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
                        end_of_then.prev_sibling_or_token().unwrap()
                    } else {
                        end_of_then
                    };
                let mut new_if_and_then_statements =
                    new_if_expr.syntax().children_with_tokens().chain(
                        then_block_items
                            .syntax()
                            .children_with_tokens()
                            .skip(1)
                            .take_while(|i| *i != end_of_then),
                    );
                replace_children(
                    &parent_block.syntax(),
                    RangeInclusive::new(
                        if_expr.clone().syntax().clone().into(),
                        if_expr.syntax().clone().into(),
                    ),
                    &mut new_if_and_then_statements,
                )
            }
            _ => {
                // If-let.
                let new_match_expr =
                    if_indent_level.increase_indent(make::let_match_early(expr, early_expression));
                let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
                let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
                let end_of_then =
                    if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
                        end_of_then.prev_sibling_or_token().unwrap()
                    } else {
                        end_of_then
                    };
                let mut then_statements = new_match_expr.syntax().children_with_tokens().chain(
                    then_block_items
                        .syntax()
                        .children_with_tokens()
                        .skip(1)
                        .take_while(|i| *i != end_of_then),
                );
                let new_block = replace_children(
                    &parent_block.syntax(),
                    RangeInclusive::new(
                        if_expr.clone().syntax().clone().into(),
                        if_expr.syntax().clone().into(),
                    ),
                    &mut then_statements,
                );
                new_block
            }
        };
        edit.target(if_expr.syntax().text_range());
        edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap());
        edit.set_cursor(cursor_position);
    })
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::helpers::{check_assist, check_assist_not_applicable};

    #[test]
    fn convert_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                bar();
                if<|> true {
                    foo();

                    //comment
                    bar();
                }
            }
            "#,
            r#"
            fn main() {
                bar();
                if<|> !true {
                    return;
                }
                foo();

                //comment
                bar();
            }
            "#,
        );
    }

    #[test]
    fn convert_let_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main(n: Option<String>) {
                bar();
                if<|> let Some(n) = n {
                    foo(n);

                    //comment
                    bar();
                }
            }
            "#,
            r#"
            fn main(n: Option<String>) {
                bar();
                le<|>t n = match n {
                    Some(it) => it,
                    None => return,
                };
                foo(n);

                //comment
                bar();
            }
            "#,
        );
    }

    #[test]
    fn convert_inside_while() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                while true {
                    if<|> true {
                        foo();
                        bar();
                    }
                }
            }
            "#,
            r#"
            fn main() {
                while true {
                    if<|> !true {
                        continue;
                    }
                    foo();
                    bar();
                }
            }
            "#,
        );
    }

    #[test]
    fn convert_let_inside_while() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                while true {
                    if<|> let Some(n) = n {
                        foo(n);
                        bar();
                    }
                }
            }
            "#,
            r#"
            fn main() {
                while true {
                    le<|>t n = match n {
                        Some(it) => it,
                        None => continue,
                    };
                    foo(n);
                    bar();
                }
            }
            "#,
        );
    }

    #[test]
    fn convert_inside_loop() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                loop {
                    if<|> true {
                        foo();
                        bar();
                    }
                }
            }
            "#,
            r#"
            fn main() {
                loop {
                    if<|> !true {
                        continue;
                    }
                    foo();
                    bar();
                }
            }
            "#,
        );
    }

    #[test]
    fn convert_let_inside_loop() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                loop {
                    if<|> let Some(n) = n {
                        foo(n);
                        bar();
                    }
                }
            }
            "#,
            r#"
            fn main() {
                loop {
                    le<|>t n = match n {
                        Some(it) => it,
                        None => continue,
                    };
                    foo(n);
                    bar();
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_already_converted_if() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if<|> true {
                    return;
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_already_converted_loop() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                loop {
                    if<|> true {
                        continue;
                    }
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_return() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if<|> true {
                    return
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_else_branch() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if<|> true {
                    foo();
                } else {
                    bar()
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_statements_aftert_if() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if<|> true {
                    foo();
                }
                bar();
            }
            "#,
        );
    }

    #[test]
    fn ignore_statements_inside_if() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if false {
                    if<|> true {
                        foo();
                    }
                }
            }
            "#,
        );
    }
}
<|endoftext|>