<commit_before>// Copyright 2016 The Grin 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 grin_core as core;
extern crate grin_p2p as p2p;
extern crate env_logger;
extern crate futures;
extern crate tokio_core;

use std::net::SocketAddr;
use std::sync::Arc;
use std::time;

use futures::future::Future;
use tokio_core::net::TcpStream;
use tokio_core::reactor::{self, Core};

use core::core::{Transaction, Block};
use core::ser;
use core::core::target::Difficulty;
use p2p::Peer;
use p2p::NetAdapter;

mod mocks;
use mocks::{DummyAdapter, RejectingAdapter};

// Starts a server and connects a client peer to it to check handshake,
// followed by a ping/pong exchange to make sure the connection is live.
#[test]
fn peer_handshake() {
	env_logger::init().unwrap();

	let mut evtlp = Core::new().unwrap();
	let handle = evtlp.handle();
	let p2p_conf = p2p::P2PConfig::default();
	let net_adapter = Arc::new(DummyAdapter {});
	let server = p2p::Server::new(p2p::UNKNOWN, p2p_conf, net_adapter.clone());
	let run_server = server.start(handle.clone());
	let my_addr = "127.0.0.1:5000".parse().unwrap();

	let phandle = handle.clone();
	let rhandle = handle.clone();
	let timeout = reactor::Timeout::new(time::Duration::new(1, 0), &handle).unwrap();
	let timeout_send = reactor::Timeout::new(time::Duration::new(2, 0), &handle).unwrap();
	handle.spawn(timeout.from_err()
		.and_then(move |_| {
			let p2p_conf = p2p::P2PConfig::default();
			let addr = SocketAddr::new(p2p_conf.host, p2p_conf.port);
			let socket = TcpStream::connect(&addr, &phandle).map_err(|e| p2p::Error::Connection(e));
			socket.and_then(move |socket| {
					Peer::connect(socket,
					              p2p::UNKNOWN,
					              Difficulty::one(),
					              my_addr,
					              &p2p::handshake::Handshake::new())
				})
				.and_then(move |(socket, peer)| {
					rhandle.spawn(peer.run(socket, net_adapter.clone()).map_err(|e| {
						panic!("Client run failed: {:?}", e);
					}));
					peer.send_ping().unwrap();
					timeout_send.from_err().map(|_| peer)
				})
				.and_then(|peer| {
					let (sent, recv) = peer.transmitted_bytes();
					assert!(sent > 0);
					assert!(recv > 0);
					Ok(())
				})
				.and_then(|_| {
					assert!(server.peer_count() > 0);
					server.stop();
					Ok(())
				})
		})
		.map_err(|e| {
			panic!("Client connection failed: {:?}", e);
		}));

	evtlp.run(run_server).unwrap();

}

/// Starts a server with complete rejection policy, connects a peer, send any tx payload + check peer is banned
#[test]
fn peer_banning() {
	env_logger::init().unwrap();

	let mut evtlp = Core::new().unwrap();
	let handle = evtlp.handle();
	let p2p_conf = p2p::P2PConfig::default();
	let net_adapter = Arc::new(RejectingAdapter {});
	let server = p2p::Server::new(p2p::UNKNOWN, p2p_conf, net_adapter.clone());
	let run_server = server.start(handle.clone());
	let my_addr = "127.0.0.1:5000".parse().unwrap();

	let phandle = handle.clone();
	let rhandle = handle.clone();
	let timeout = reactor::Timeout::new(time::Duration::new(1, 0), &handle).unwrap();
	let timeout_send = reactor::Timeout::new(time::Duration::new(2, 0), &handle).unwrap();

	handle.spawn(timeout.from_err()
		.and_then(move |_| {
			let p2p_conf = p2p::P2PConfig::default();
			let addr = SocketAddr::new(p2p_conf.host, p2p_conf.port);
			let socket = TcpStream::connect(&addr, &phandle).map_err(|e| p2p::Error::Connection(e));
			socket.and_then(move |socket| {
					Peer::connect(socket,
					              p2p::UNKNOWN,
					              Difficulty::one(),
					              my_addr,
					              &p2p::handshake::Handshake::new())
				})
				.and_then(move |(socket, peer)| {
					rhandle.spawn(peer.run(socket, net_adapter.clone()).map_err(|e| {
						panic!("Client run failed: {:?}", e);
					}));
					server.broadcast_block(&Block::default());
					Ok((server, peer))
				})
				.and_then(|(server, peer)| {
					println!("{:?}", peer.info);
					server.stop();
					Ok(())
				})
		})
		.map_err(|e| {
			panic!("Client connection failed: {:?}", e);
		}));

	evtlp.run(run_server).unwrap();
}
<commit_msg>Implement Peer Banning Tests<commit_after>// Copyright 2016 The Grin 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 grin_core as core;
extern crate grin_p2p as p2p;
extern crate env_logger;
extern crate futures;
extern crate tokio_core;

use std::net::SocketAddr;
use std::sync::Arc;
use std::time;

use futures::future::Future;
use tokio_core::net::TcpStream;
use tokio_core::reactor::{self, Core};

use core::core::{Transaction, Block};
use core::ser;
use core::core::target::Difficulty;
use p2p::Peer;
use p2p::NetAdapter;

mod mocks;
use mocks::{DummyAdapter, RejectingAdapter};

// Starts a server and connects a client peer to it to check handshake,
// followed by a ping/pong exchange to make sure the connection is live.
#[test]
fn peer_handshake() {
	env_logger::init().unwrap();

	let mut evtlp = Core::new().unwrap();
	let handle = evtlp.handle();
	let p2p_conf = p2p::P2PConfig::default();
	let net_adapter = Arc::new(DummyAdapter {});
	let server = p2p::Server::new(p2p::UNKNOWN, p2p_conf, net_adapter.clone());
	let run_server = server.start(handle.clone());
	let my_addr = "127.0.0.1:5000".parse().unwrap();

	let phandle = handle.clone();
	let rhandle = handle.clone();
	let timeout = reactor::Timeout::new(time::Duration::new(1, 0), &handle).unwrap();
	let timeout_send = reactor::Timeout::new(time::Duration::new(2, 0), &handle).unwrap();

	handle.spawn(timeout.from_err()
		.and_then(move |_| {
			let p2p_conf = p2p::P2PConfig::default();
			let addr = SocketAddr::new(p2p_conf.host, p2p_conf.port);
			let socket = TcpStream::connect(&addr, &phandle).map_err(|e| p2p::Error::Connection(e));
			socket.and_then(move |socket| {
					Peer::connect(socket,
					              p2p::UNKNOWN,
					              Difficulty::one(),
					              my_addr,
					              &p2p::handshake::Handshake::new())
				})
				.and_then(move |(socket, peer)| {
					rhandle.spawn(peer.run(socket, net_adapter.clone()).map_err(|e| {
						panic!("Client run failed: {:?}", e);
					}));
					peer.send_ping().unwrap();
					timeout_send.from_err().map(|_| peer)
				})
				.and_then(|peer| {
					let (sent, recv) = peer.transmitted_bytes();
					assert!(sent > 0);
					assert!(recv > 0);
					Ok(())
				})
				.and_then(|_| {
					assert!(server.peer_count() > 0);
					server.stop();
					Ok(())
				})
		})
		.map_err(|e| {
			panic!("Client connection failed: {:?}", e);
		}));

	evtlp.run(run_server).unwrap();

}

/// Starts a server with complete rejection policy, connects a peer, send any tx payload + check peer is banned
#[test]
fn peer_banning() {
	// env_logger::init().unwrap();

	let mut evtlp = Core::new().unwrap();
	let handle = evtlp.handle();
	let p2p_conf = p2p::P2PConfig::default();
	let net_adapter = Arc::new(RejectingAdapter {});
	let server = p2p::Server::new(p2p::UNKNOWN, p2p_conf, net_adapter.clone());
	let run_server = server.start(handle.clone());
	let my_addr: SocketAddr = "127.0.0.1:5000".parse().unwrap();

	let phandle = handle.clone();
	let rhandle = handle.clone();
	let timeout = reactor::Timeout::new(time::Duration::new(1, 0), &handle).unwrap();
	let timeout_send = reactor::Timeout::new(time::Duration::new(2, 0), &handle).unwrap();

	handle.spawn(timeout.from_err()
		.and_then(move |_| {
			let p2p_conf = p2p::P2PConfig::default();
			let addr = SocketAddr::new(p2p_conf.host, p2p_conf.port);
			let socket = TcpStream::connect(&addr, &phandle).map_err(|e| p2p::Error::Connection(e));
			socket.and_then(move |socket| {
					Peer::connect(socket,
					              p2p::UNKNOWN,
					              Difficulty::one(),
					              my_addr.clone(),
					              &p2p::handshake::Handshake::new())
				})
				.and_then(move |(socket, peer)| {
					rhandle.spawn(peer.run(socket, net_adapter.clone()).map_err(|e| {
						panic!("Client run failed: {:?}", e);
					}));
					peer.send_block(&Block::default());
					timeout_send.from_err().map(|_| peer)
				})
				.and_then(move |peer| {
					assert!(server.peer_count() > 0);

					let s_peer = server.get_peer(my_addr.clone()).expect("get server peer by address");
					assert!(s_peer.is_banned(), "Peer must be banned");

					server.stop();
					Ok(())
				})
		})
		.map_err(|e| {
			panic!("Client connection failed: {:?}", e);
		}));

	evtlp.run(run_server).unwrap();
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;

use backend::Backend;
use platform::platform::Platform;
use provider::Providers;
use provider::file;
use provider::file::FileProvider;
use provider::service;
use provider::service::ServiceProvider;

#[derive(Clone, Debug)]
pub struct RedHat {
    name: String,
    release: String,
}

impl Platform for RedHat {
    fn new() -> RedHat {
        RedHat {
            name: "".to_string(),
            release: "".to_string(),
        }
    }

    fn inline_detector(&self) -> Option<Box<Platform>> {
        let mut file = match File::open("/etc/redhat-release") {
            Ok(f) => f,
            Err(_) => return None,
        };

        let mut contents = String::new();
        let _ = file.read_to_string(&mut contents);

        self.detect_by_redhat_release(&contents)
    }

    fn shell_detector(&self, b: &Backend) -> Option<Box<Platform>> {
        let contents = match b.run_command("cat /etc/redhat-release") {
            Err(_) => return None,
            Ok(f) => f,
        };

        self.detect_by_redhat_release(&contents.stdout)
    }

    fn get_providers(&self) -> Box<Providers> {
        let fp = FileProvider {
            inline: Box::new(file::inline::posix::Posix),
            shell: Box::new(file::shell::linux::Linux),
        };

        let sp = ServiceProvider {
            inline: Box::new(service::inline::null::Null),
            shell: Box::new(service::shell::null::Null),
        };

        let p = Providers {
            file: Box::new(fp),
            service: Box::new(sp),
        };

        Box::new(p)
    }
}

impl RedHat {
    fn detect_by_redhat_release(&self, contents: &str) -> Option<Box<Platform>> {
        let mut line = contents.split(" ");
        let r = RedHat {
            name: line.nth(0).unwrap().trim().to_string(),
            release: line.nth(2).unwrap().trim().to_string(),
        };

        Some(Box::new(r))
    }
}
<commit_msg>Use systemd provider in redhat<commit_after>use std::fs::File;
use std::io::prelude::*;

use backend::Backend;
use platform::platform::Platform;
use provider::Providers;
use provider::file;
use provider::file::FileProvider;
use provider::service;
use provider::service::ServiceProvider;

#[derive(Clone, Debug)]
pub struct RedHat {
    name: String,
    release: String,
}

impl Platform for RedHat {
    fn new() -> RedHat {
        RedHat {
            name: "".to_string(),
            release: "".to_string(),
        }
    }

    fn inline_detector(&self) -> Option<Box<Platform>> {
        let mut file = match File::open("/etc/redhat-release") {
            Ok(f) => f,
            Err(_) => return None,
        };

        let mut contents = String::new();
        let _ = file.read_to_string(&mut contents);

        self.detect_by_redhat_release(&contents)
    }

    fn shell_detector(&self, b: &Backend) -> Option<Box<Platform>> {
        let contents = match b.run_command("cat /etc/redhat-release") {
            Err(_) => return None,
            Ok(f) => f,
        };

        self.detect_by_redhat_release(&contents.stdout)
    }

    fn get_providers(&self) -> Box<Providers> {
        let fp = FileProvider {
            inline: Box::new(file::inline::posix::Posix),
            shell: Box::new(file::shell::linux::Linux),
        };

        let sp = ServiceProvider {
            inline: Box::new(service::inline::systemd::Systemd),
            shell: Box::new(service::shell::null::Null),
        };

        let p = Providers {
            file: Box::new(fp),
            service: Box::new(sp),
        };

        Box::new(p)
    }
}

impl RedHat {
    fn detect_by_redhat_release(&self, contents: &str) -> Option<Box<Platform>> {
        let mut line = contents.split(" ");
        let r = RedHat {
            name: line.nth(0).unwrap().trim().to_string(),
            release: line.nth(2).unwrap().trim().to_string(),
        };

        Some(Box::new(r))
    }
}
<|endoftext|>


<commit_before>use crate::{api::prelude::*, proc_macros::*};

#[derive(Debug, Copy, Clone)]
enum Action {
    Press(Mouse),
    Release(Mouse),
    Scroll(Point),
}

/// The `MouseBehaviorState` handles the `MouseBehavior` widget.
#[derive(Default, AsAny)]
pub struct MouseBehaviorState {
    has_delta: bool,
    target: Entity,
}

impl State for MouseBehaviorState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.target = (*MouseBehavior::target_ref(&ctx.widget())).into();
    }

    fn messages(
        &mut self,
        mut messages: MessageReader,
        _registry: &mut Registry,
        ctx: &mut Context,
    ) {
        for message in messages.read::<Action>() {
            match message {
                Action::Press(_) => {
                    ctx.get_widget(self.target).set("pressed", true);
                    toggle_flag("pressed", &mut ctx.get_widget(self.target));
                }
                Action::Release(p) => {
                    if !*MouseBehavior::pressed_ref(&ctx.widget()) {
                        return;
                    }

                    ctx.get_widget(self.target).set("pressed", false);
                    toggle_flag("pressed", &mut ctx.get_widget(self.target));

                    if check_mouse_condition(p.position, &ctx.widget()) {
                        ctx.event_adapter().push_event(
                            self.target,
                            ClickEvent {
                                position: p.position,
                            },
                        );
                    }
                }
                Action::Scroll(p) => {
                    MouseBehavior::position_set(&mut ctx.widget(), p);
                    self.has_delta = true;
                }
            }

            ctx.get_widget(self.target).update(false);
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context) {
        if self.has_delta {
            MouseBehavior::delta_set(&mut ctx.widget(), Point::default());
            self.has_delta = false;
        }
    }
}

widget!(
    /// The `MouseBehavior` widget will take care to handle the actions,
    /// that should be triggered if the mouse pressed event is triggered.
    ///
    /// **style:** `check-box`
    MouseBehavior<MouseBehaviorState>: MouseHandler {
        /// Sets or shares the target of the behavior.
        target: u32,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the (wheel, scroll) delta property.
        delta: Point
    }
);

impl Template for MouseBehavior {
    fn template(self, id: Entity, _: &mut BuildContext) -> Self {
        self.name("MouseBehavior")
            .delta(0.0)
            .pressed(false)
            .on_mouse_down(move |ctx, m| {
                ctx.send_message(Action::Press(m), id);
                false
            })
            .on_mouse_up(move |ctx, m| {
                ctx.send_message(Action::Release(m), id);
            })
            .on_scroll(move |ctx, p| {
                ctx.send_message(Action::Scroll(p), id);
                false
            })
    }
}
<commit_msg>orbtk_widgets: fix typo bug in `mouse_behavior`<commit_after>use crate::{api::prelude::*, proc_macros::*};

#[derive(Debug, Copy, Clone)]
enum Action {
    Press(Mouse),
    Release(Mouse),
    Scroll(Point),
}

/// The `MouseBehaviorState` handles the `MouseBehavior` widget.
#[derive(Default, AsAny)]
pub struct MouseBehaviorState {
    has_delta: bool,
    target: Entity,
}

impl State for MouseBehaviorState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.target = (*MouseBehavior::target_ref(&ctx.widget())).into();
    }

    fn messages(
        &mut self,
        mut messages: MessageReader,
        _registry: &mut Registry,
        ctx: &mut Context,
    ) {
        for message in messages.read::<Action>() {
            match message {
                Action::Press(_) => {
                    ctx.get_widget(self.target).set("pressed", true);
                    toggle_flag("pressed", &mut ctx.get_widget(self.target));
                }
                Action::Release(p) => {
                    if !*MouseBehavior::pressed_ref(&ctx.widget()) {
                        return;
                    }

                    ctx.get_widget(self.target).set("pressed", false);
                    toggle_flag("pressed", &mut ctx.get_widget(self.target));

                    if check_mouse_condition(p.position, &ctx.widget()) {
                        ctx.event_adapter().push_event(
                            self.target,
                            ClickEvent {
                                position: p.position,
                            },
                        );
                    }
                }
                Action::Scroll(p) => {
                    MouseBehavior::position_set(&mut ctx.widget(), p);
                    self.has_delta = true;
                }
            }

            ctx.get_widget(self.target).update(false);
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context) {
        if self.has_delta {
            MouseBehavior::delta_set(&mut ctx.widget(), Point::default());
            self.has_delta = false;
        }
    }
}

widget!(
    /// The `MouseBehavior` widget will take care to handle the actions,
    /// that should be triggered if the mouse pressed event is triggered.
    ///
    /// **style:** `check_box`
    MouseBehavior<MouseBehaviorState>: MouseHandler {
        /// Sets or shares the target of the behavior.
        target: u32,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the (wheel, scroll) delta property.
        delta: Point
    }
);

impl Template for MouseBehavior {
    fn template(self, id: Entity, _: &mut BuildContext) -> Self {
        self.name("MouseBehavior")
            .delta(0.0)
            .pressed(false)
            .on_mouse_down(move |ctx, m| {
                ctx.send_message(Action::Press(m), id);
                false
            })
            .on_mouse_up(move |ctx, m| {
                ctx.send_message(Action::Release(m), id);
            })
            .on_scroll(move |ctx, p| {
                ctx.send_message(Action::Scroll(p), id);
                false
            })
    }
}
<|endoftext|>


<commit_before>use std::f64::consts::PI;

use crate::{
    prelude::*,
    render::RenderContext2D,
    utils,
    utils::{Brush, Point, Rectangle, Thickness},
};

pub struct RectangleRenderObject;

impl RectangleRenderObject {
    // Renders rectangle with border and without radius.
    fn render_bordered_rect_path(
        &self,
        render_context_2_d: &mut RenderContext2D,
        rect: Rectangle,
        brush: utils::Brush,
        border_brush: utils::Brush,
        border_thickness: Thickness,
    ) {
        render_context_2_d.rect(rect.x, rect.y, rect.width, rect.height);

        if !brush.is_transparent() {
            render_context_2_d.set_fill_style(brush);
            render_context_2_d.fill();
        }

        if !border_brush.is_transparent() {
            render_context_2_d.set_line_width(border_thickness.left());
            render_context_2_d.set_stroke_style(border_brush);
            render_context_2_d.stroke();
        }
    }

    // Builds rectangle path with radius and without border.
    fn render_rounded_rect_path(
        &self,
        render_context_2_d: &mut RenderContext2D,
        x: f64,
        y: f64,
        width: f64,
        height: f64,
        radius: f64,
    ) {
        let r = x + width;
        let b = y + height;
        render_context_2_d.move_to(x + radius, y);
        render_context_2_d.line_to(r - radius, y);
        render_context_2_d.quadratic_curve_to(r, y, r, y + radius);
        render_context_2_d.line_to(r, y + height - radius);
        render_context_2_d.quadratic_curve_to(r, b, r - radius, b);
        render_context_2_d.line_to(x + radius, b);
        render_context_2_d.quadratic_curve_to(x, b, x, b - radius);
        render_context_2_d.line_to(x, y + radius);
        render_context_2_d.quadratic_curve_to(x, y, x + radius, y);
        render_context_2_d.close_path();
    }

    fn render_circle(
        &self,
        render_context_2_d: &mut RenderContext2D,
        x: f64,
        y: f64,
        width: f64,
        height: f64,
        radius: f64,
    ) {
        render_context_2_d.move_to(x, y);
        render_context_2_d.arc(x + width / 2.0, y + height / 2.0, radius, 0.0, 2. * PI);
        render_context_2_d.close_path();
    }

    fn render_bordered_circle(
        &self,
        render_context_2_d: &mut RenderContext2D,
        x: f64,
        y: f64,
        width: f64,
        height: f64,
        radius: f64,
        brush: utils::Brush,
        border_brush: utils::Brush,
        border_thickness: Thickness,
    ) {
        self.render_circle(render_context_2_d, x, y, width, height, radius);

        if !brush.is_transparent() {
            render_context_2_d.set_fill_style(brush);
            render_context_2_d.fill();
        }

        if !border_brush.is_transparent() {
            render_context_2_d.set_line_width(border_thickness.left());
            render_context_2_d.set_stroke_style(border_brush);
            render_context_2_d.stroke();
        }
    }

    // Renders rectangle with border and radius.
    fn render_rounded_bordered_rect_path(
        &self,
        render_context_2_d: &mut RenderContext2D,
        rect: Rectangle,
        radius: f64,
        brush: utils::Brush,
        border_brush: utils::Brush,
        border_thickness: Thickness,
    ) {
        self.render_rounded_rect_path(
            render_context_2_d,
            rect.x,
            rect.y,
            rect.width,
            rect.height,
            radius,
        );

        if !brush.is_transparent() {
            render_context_2_d.set_fill_style(brush);
            render_context_2_d.fill();
        }

        if !border_brush.is_transparent() {
            render_context_2_d.set_line_width(border_thickness.left());
            render_context_2_d.set_stroke_style(border_brush);
            render_context_2_d.stroke();
        }
    }

    pub(crate) fn ensure_no_corner_overlap(
        border_radius: &mut f64,
        bounds: Rectangle
    ) {
        let mut ratio = 1.0;
        let sum = 2.0 * *border_radius;
        if bounds.width() < sum {
            ratio = f64::min(ratio, bounds.width() / sum);
        }
        if bounds.height() < sum {
            ratio = f64::min(ratio, bounds.height() / sum);
}
        if ratio < 1. {
            *border_radius *= ratio;
        }
    }
}

impl Into<Box<dyn RenderObject>> for RectangleRenderObject {
    fn into(self) -> Box<dyn RenderObject> {
        Box::new(self)
    }
}

impl RenderObject for RectangleRenderObject {
    fn render_self(&self, ctx: &mut Context<'_>, global_position: &Point) {
        let (bounds, background, border_radius, border_thickness, border_brush) = {
            let widget = ctx.widget();
            (
                widget.clone::<Rectangle>("bounds"),
                widget.get::<Brush>("background").clone(),
                widget.clone_or_default::<f64>("border_radius"),
                widget.clone_or_default::<Thickness>("border_width"),
                widget.clone_or_default::<Brush>("border_brush"),
            )
        };

        if (bounds.width() == 0.0
            || bounds.height() == 0.0
            || (background.is_transparent() && border_brush.is_transparent()))
            && (border_thickness.left == 0.0
                && border_thickness.top == 0.0
                && border_thickness.right == 0.0
                && border_thickness.bottom == 0.0)
        {
            return;
        }

        let has_thickness = border_thickness.left > 0.0
            || border_thickness.top > 0.0
            || border_thickness.right > 0.0
            || border_thickness.bottom > 0.0;

        ctx.render_context_2_d().begin_path();
        let mut border_radius = border_radius;
        Self::ensure_no_corner_overlap(&mut border_radius, bounds);
        if bounds.width() == bounds.height() {
            if !has_thickness {
                self.render_circle(
                    ctx.render_context_2_d(),
                    global_position.x + bounds.x(),
                    global_position.y + bounds.y(),
                    bounds.width(),
                    bounds.height(),
                    border_radius,
                );
                ctx.render_context_2_d().set_fill_style(background);
                ctx.render_context_2_d().fill();
            } else {
                self.render_bordered_circle(
                    ctx.render_context_2_d(),
                    global_position.x + bounds.x(),
                    global_position.y + bounds.y(),
                    bounds.width(),
                    bounds.height(),
                    border_radius,
                    background,
                    border_brush,
                    border_thickness,
                );
            }
            return;
        } else if border_radius > 0. && has_thickness {
            self.render_rounded_bordered_rect_path(
                ctx.render_context_2_d(),
                Rectangle::new(
                    global_position.x + bounds.x(),
                    global_position.y + bounds.y(),
                    bounds.width(),
                    bounds.height(),
                ),
                border_radius,
                background,
                border_brush,
                border_thickness,
            );
        } else if border_radius > 0. {
            self.render_rounded_rect_path(
                ctx.render_context_2_d(),
                global_position.x + bounds.x(),
                global_position.y + bounds.y(),
                bounds.width(),
                bounds.height(),
                border_radius,
            );

            ctx.render_context_2_d().set_fill_style(background);
            ctx.render_context_2_d().fill();
        } else if has_thickness {
            self.render_bordered_rect_path(
                ctx.render_context_2_d(),
                Rectangle::new(
                    global_position.x + bounds.x(),
                    global_position.y + bounds.y(),
                    bounds.width(),
                    bounds.height(),
                ),
                background,
                border_brush,
                border_thickness,
            );
        } else {
            ctx.render_context_2_d().rect(
                global_position.x + bounds.x(),
                global_position.y + bounds.y(),
                bounds.width(),
                bounds.height(),
            );
            ctx.render_context_2_d().set_fill_style(background);
            ctx.render_context_2_d().fill();
        }
    }
}
<commit_msg>Reset PR #180 .<commit_after>use std::f64::consts::PI;

use crate::{
    prelude::*,
    render::RenderContext2D,
    utils,
    utils::{Brush, Point, Rectangle, Thickness},
};

pub struct RectangleRenderObject;

impl RectangleRenderObject {
    // Renders rectangle with border and without radius.
    fn render_bordered_rect_path(
        &self,
        render_context_2_d: &mut RenderContext2D,
        rect: Rectangle,
        brush: utils::Brush,
        border_brush: utils::Brush,
        border_thickness: Thickness,
    ) {
        render_context_2_d.rect(rect.x, rect.y, rect.width, rect.height);

        if !brush.is_transparent() {
            render_context_2_d.set_fill_style(brush);
            render_context_2_d.fill();
        }

        if !border_brush.is_transparent() {
            render_context_2_d.set_line_width(border_thickness.left());
            render_context_2_d.set_stroke_style(border_brush);
            render_context_2_d.stroke();
        }
    }

    // Builds rectangle path with radius and without border.
    fn render_rounded_rect_path(
        &self,
        render_context_2_d: &mut RenderContext2D,
        x: f64,
        y: f64,
        width: f64,
        height: f64,
        radius: f64,
    ) {
        let r = x + width;
        let b = y + height;
        render_context_2_d.move_to(x + radius, y);
        render_context_2_d.line_to(r - radius, y);
        render_context_2_d.quadratic_curve_to(r, y, r, y + radius);
        render_context_2_d.line_to(r, y + height - radius);
        render_context_2_d.quadratic_curve_to(r, b, r - radius, b);
        render_context_2_d.line_to(x + radius, b);
        render_context_2_d.quadratic_curve_to(x, b, x, b - radius);
        render_context_2_d.line_to(x, y + radius);
        render_context_2_d.quadratic_curve_to(x, y, x + radius, y);
        render_context_2_d.close_path();
    }

    fn render_circle(
        &self,
        render_context_2_d: &mut RenderContext2D,
        x: f64,
        y: f64,
        width: f64,
        height: f64,
        radius: f64,
    ) {
        render_context_2_d.move_to(x, y);
        render_context_2_d.arc(x + width / 2.0, y + height / 2.0, radius, 0.0, 2. * PI);
        render_context_2_d.close_path();
    }

    fn render_bordered_circle(
        &self,
        render_context_2_d: &mut RenderContext2D,
        x: f64,
        y: f64,
        width: f64,
        height: f64,
        radius: f64,
        brush: utils::Brush,
        border_brush: utils::Brush,
        border_thickness: Thickness,
    ) {
        self.render_circle(render_context_2_d, x, y, width, height, radius);

        if !brush.is_transparent() {
            render_context_2_d.set_fill_style(brush);
            render_context_2_d.fill();
        }

        if !border_brush.is_transparent() {
            render_context_2_d.set_line_width(border_thickness.left());
            render_context_2_d.set_stroke_style(border_brush);
            render_context_2_d.stroke();
        }
    }

    // Renders rectangle with border and radius.
    fn render_rounded_bordered_rect_path(
        &self,
        render_context_2_d: &mut RenderContext2D,
        rect: Rectangle,
        radius: f64,
        brush: utils::Brush,
        border_brush: utils::Brush,
        border_thickness: Thickness,
    ) {
        self.render_rounded_rect_path(
            render_context_2_d,
            rect.x,
            rect.y,
            rect.width,
            rect.height,
            radius,
        );

        if !brush.is_transparent() {
            render_context_2_d.set_fill_style(brush);
            render_context_2_d.fill();
        }

        if !border_brush.is_transparent() {
            render_context_2_d.set_line_width(border_thickness.left());
            render_context_2_d.set_stroke_style(border_brush);
            render_context_2_d.stroke();
        }
    }
}

impl Into<Box<dyn RenderObject>> for RectangleRenderObject {
    fn into(self) -> Box<dyn RenderObject> {
        Box::new(self)
    }
}

impl RenderObject for RectangleRenderObject {
    fn render_self(&self, ctx: &mut Context<'_>, global_position: &Point) {
        let (bounds, background, border_radius, border_thickness, border_brush) = {
            let widget = ctx.widget();
            (
                widget.clone::<Rectangle>("bounds"),
                widget.get::<Brush>("background").clone(),
                widget.clone_or_default::<f64>("border_radius"),
                widget.clone_or_default::<Thickness>("border_width"),
                widget.clone_or_default::<Brush>("border_brush"),
            )
        };

        if (bounds.width() == 0.0
            || bounds.height() == 0.0
            || (background.is_transparent() && border_brush.is_transparent()))
            && (border_thickness.left == 0.0
                && border_thickness.top == 0.0
                && border_thickness.right == 0.0
                && border_thickness.bottom == 0.0)
        {
            return;
        }

        let has_thickness = border_thickness.left > 0.0
            || border_thickness.top > 0.0
            || border_thickness.right > 0.0
            || border_thickness.bottom > 0.0;

        ctx.render_context_2_d().begin_path();

        if bounds.width() == bounds.height() && border_radius >= bounds.width() / 2.0 {
            if !has_thickness {
                self.render_circle(
                    ctx.render_context_2_d(),
                    global_position.x + bounds.x(),
                    global_position.y + bounds.y(),
                    bounds.width(),
                    bounds.height(),
                    border_radius,
                );
                ctx.render_context_2_d().set_fill_style(background);
                ctx.render_context_2_d().fill();
            } else {
                self.render_bordered_circle(
                    ctx.render_context_2_d(),
                    global_position.x + bounds.x(),
                    global_position.y + bounds.y(),
                    bounds.width(),
                    bounds.height(),
                    border_radius,
                    background,
                    border_brush,
                    border_thickness,
                );
            }
            return;
        } else if border_radius > 0. && has_thickness {
            self.render_rounded_bordered_rect_path(
                ctx.render_context_2_d(),
                Rectangle::new(
                    global_position.x + bounds.x(),
                    global_position.y + bounds.y(),
                    bounds.width(),
                    bounds.height(),
                ),
                border_radius,
                background,
                border_brush,
                border_thickness,
            );
        } else if border_radius > 0. {
            self.render_rounded_rect_path(
                ctx.render_context_2_d(),
                global_position.x + bounds.x(),
                global_position.y + bounds.y(),
                bounds.width(),
                bounds.height(),
                border_radius,
            );

            ctx.render_context_2_d().set_fill_style(background);
            ctx.render_context_2_d().fill();
        } else if has_thickness {
            self.render_bordered_rect_path(
                ctx.render_context_2_d(),
                Rectangle::new(
                    global_position.x + bounds.x(),
                    global_position.y + bounds.y(),
                    bounds.width(),
                    bounds.height(),
                ),
                background,
                border_brush,
                border_thickness,
            );
        } else {
            ctx.render_context_2_d().rect(
                global_position.x + bounds.x(),
                global_position.y + bounds.y(),
                bounds.width(),
                bounds.height(),
            );
            ctx.render_context_2_d().set_fill_style(background);
            ctx.render_context_2_d().fill();
        }
    }
}
<|endoftext|>


<commit_before>//! This module is concerned with finding methods that a given type provides.
//! For details about how this works in rustc, see the method lookup page in the
//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
use std::sync::Arc;

use arrayvec::ArrayVec;
use rustc_hash::FxHashMap;

use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef};
use crate::{
    db::HirDatabase,
    generics::HasGenericParams,
    impl_block::{ImplBlock, ImplId},
    nameres::CrateModuleId,
    resolve::Resolver,
    ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy},
    ty::{Ty, TypeCtor},
    AssocItem, Crate, Function, Module, Name, Trait,
};

/// This is used as a key for indexing impls.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TyFingerprint {
    Apply(TypeCtor),
}

impl TyFingerprint {
    /// Creates a TyFingerprint for looking up an impl. Only certain types can
    /// have impls: if we have some `struct S`, we can have an `impl S`, but not
    /// `impl &S`. Hence, this will return `None` for reference types and such.
    fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
        match ty {
            Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)),
            _ => None,
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub struct CrateImplBlocks {
    /// To make sense of the CrateModuleIds, we need the source root.
    krate: Crate,
    impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>,
    impls_by_trait: FxHashMap<Trait, Vec<(CrateModuleId, ImplId)>>,
}

impl CrateImplBlocks {
    pub fn lookup_impl_blocks<'a>(&'a self, ty: &Ty) -> impl Iterator<Item = ImplBlock> + 'a {
        let fingerprint = TyFingerprint::for_impl(ty);
        fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                ImplBlock::from_id(module, *impl_id)
            },
        )
    }

    pub fn lookup_impl_blocks_for_trait<'a>(
        &'a self,
        tr: Trait,
    ) -> impl Iterator<Item = ImplBlock> + 'a {
        self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                ImplBlock::from_id(module, *impl_id)
            },
        )
    }

    pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplBlock> + 'a {
        self.impls.values().chain(self.impls_by_trait.values()).flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                ImplBlock::from_id(module, *impl_id)
            },
        )
    }

    fn collect_recursive(&mut self, db: &impl HirDatabase, module: Module) {
        let module_impl_blocks = db.impls_in_module(module);

        for (impl_id, _) in module_impl_blocks.impls.iter() {
            let impl_block = ImplBlock::from_id(module_impl_blocks.module, impl_id);

            let target_ty = impl_block.target_ty(db);

            if impl_block.target_trait(db).is_some() {
                if let Some(tr) = impl_block.target_trait_ref(db) {
                    self.impls_by_trait
                        .entry(tr.trait_)
                        .or_insert_with(Vec::new)
                        .push((module.module_id, impl_id));
                }
            } else {
                if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
                    self.impls
                        .entry(target_ty_fp)
                        .or_insert_with(Vec::new)
                        .push((module.module_id, impl_id));
                }
            }
        }

        for child in module.children(db) {
            self.collect_recursive(db, child);
        }
    }

    pub(crate) fn impls_in_crate_query(
        db: &impl HirDatabase,
        krate: Crate,
    ) -> Arc<CrateImplBlocks> {
        let mut crate_impl_blocks = CrateImplBlocks {
            krate,
            impls: FxHashMap::default(),
            impls_by_trait: FxHashMap::default(),
        };
        if let Some(module) = krate.root_module(db) {
            crate_impl_blocks.collect_recursive(db, module);
        }
        Arc::new(crate_impl_blocks)
    }
}

fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> {
    // Types like slice can have inherent impls in several crates, (core and alloc).
    // The corresponding impls are marked with lang items, so we can use them to find the required crates.
    macro_rules! lang_item_crate {
        ($db:expr, $cur_crate:expr, $($name:expr),+ $(,)?) => {{
            let mut v = ArrayVec::<[Crate; 2]>::new();
            $(
                v.push($db.lang_item($cur_crate, $name.into())?.krate($db)?);
            )+
            Some(v)
        }};
    }

    match ty {
        Ty::Apply(a_ty) => match a_ty.ctor {
            TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()),
            TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"),
            TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"),
            TypeCtor::Float(UncertainFloatTy::Known(f)) => match f.bitness {
                // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
                FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"),
                FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"),
            },
            TypeCtor::Int(UncertainIntTy::Known(i)) => {
                lang_item_crate!(db, cur_crate, i.ty_to_string())
            }
            TypeCtor::Str => lang_item_crate!(db, cur_crate, "str"),
            TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"),
            _ => None,
        },
        _ => None,
    }
}

/// Look up the method with the given name, returning the actual autoderefed
/// receiver type (but without autoref applied yet).
pub(crate) fn lookup_method(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    name: &Name,
    resolver: &Resolver,
) -> Option<(Ty, Function)> {
    iterate_method_candidates(ty, db, resolver, Some(name), |ty, f| Some((ty.clone(), f)))
}

// This would be nicer if it just returned an iterator, but that runs into
// lifetime problems, because we need to borrow temp `CrateImplBlocks`.
pub(crate) fn iterate_method_candidates<T>(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    resolver: &Resolver,
    name: Option<&Name>,
    mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
    // For method calls, rust first does any number of autoderef, and then one
    // autoref (i.e. when the method takes &self or &mut self). We just ignore
    // the autoref currently -- when we find a method matching the given name,
    // we assume it fits.

    // Also note that when we've got a receiver like &S, even if the method we
    // find in the end takes &self, we still do the autoderef step (just as
    // rustc does an autoderef and then autoref again).

    let krate = resolver.krate()?;
    for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) {
        if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback)
        {
            return Some(result);
        }
        if let Some(result) =
            iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback)
        {
            return Some(result);
        }
    }
    None
}

fn iterate_trait_method_candidates<T>(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    resolver: &Resolver,
    name: Option<&Name>,
    mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
    let krate = resolver.krate()?;
    // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
    let env = lower::trait_env(db, resolver);
    // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope
    let inherent_trait = ty.value.inherent_trait().into_iter();
    // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
    let traits_from_env = env
        .trait_predicates_for_self_ty(&ty.value)
        .map(|tr| tr.trait_)
        .flat_map(|t| t.all_super_traits(db));
    let traits = inherent_trait.chain(traits_from_env).chain(resolver.traits_in_scope(db));
    'traits: for t in traits {
        let data = t.trait_data(db);

        // FIXME this is a bit of a hack, since Chalk should say the same thing
        // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
        let inherently_implemented = ty.value.inherent_trait() == Some(t);

        // we'll be lazy about checking whether the type implements the
        // trait, but if we find out it doesn't, we'll skip the rest of the
        // iteration
        let mut known_implemented = inherently_implemented;
        for item in data.items() {
            if let AssocItem::Function(m) = *item {
                let data = m.data(db);
                if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
                    if !known_implemented {
                        let goal = generic_implements_goal(db, env.clone(), t, ty.clone());
                        if db.trait_solve(krate, goal).is_none() {
                            continue 'traits;
                        }
                    }
                    known_implemented = true;
                    if let Some(result) = callback(&ty.value, m) {
                        return Some(result);
                    }
                }
            }
        }
    }
    None
}

fn iterate_inherent_methods<T>(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    name: Option<&Name>,
    krate: Crate,
    mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
    for krate in def_crates(db, krate, &ty.value)? {
        let impls = db.impls_in_crate(krate);

        for impl_block in impls.lookup_impl_blocks(&ty.value) {
            for item in impl_block.items(db) {
                if let AssocItem::Function(f) = item {
                    let data = f.data(db);
                    if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
                        if let Some(result) = callback(&ty.value, f) {
                            return Some(result);
                        }
                    }
                }
            }
        }
    }
    None
}

pub(crate) fn implements_trait(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    resolver: &Resolver,
    krate: Crate,
    trait_: Trait,
) -> bool {
    if ty.value.inherent_trait() == Some(trait_) {
        // FIXME this is a bit of a hack, since Chalk should say the same thing
        // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
        return true;
    }
    let env = lower::trait_env(db, resolver);
    let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone());
    let solution = db.trait_solve(krate, goal);

    solution.is_some()
}

impl Ty {
    // This would be nicer if it just returned an iterator, but that runs into
    // lifetime problems, because we need to borrow temp `CrateImplBlocks`.
    pub fn iterate_impl_items<T>(
        self,
        db: &impl HirDatabase,
        krate: Crate,
        mut callback: impl FnMut(AssocItem) -> Option<T>,
    ) -> Option<T> {
        for krate in def_crates(db, krate, &self)? {
            let impls = db.impls_in_crate(krate);

            for impl_block in impls.lookup_impl_blocks(&self) {
                for item in impl_block.items(db) {
                    if let Some(result) = callback(item) {
                        return Some(result);
                    }
                }
            }
        }
        None
    }
}

/// This creates Substs for a trait with the given Self type and type variables
/// for all other parameters, to query Chalk with it.
fn generic_implements_goal(
    db: &impl HirDatabase,
    env: Arc<TraitEnvironment>,
    trait_: Trait,
    self_ty: Canonical<Ty>,
) -> Canonical<InEnvironment<super::Obligation>> {
    let mut substs = Vec::new();
    let generics = trait_.generic_params(db);
    let num_vars = self_ty.num_vars;
    substs.push(self_ty.value);
    substs.extend(
        generics
            .params_including_parent()
            .into_iter()
            .skip(1)
            .enumerate()
            .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)),
    );
    let num_vars = substs.len() - 1 + self_ty.num_vars;
    let trait_ref = TraitRef { trait_, substs: substs.into() };
    let obligation = super::Obligation::Trait(trait_ref);
    Canonical { num_vars, value: InEnvironment::new(env, obligation) }
}
<commit_msg>Add missing lang-items to `def_crates`<commit_after>//! This module is concerned with finding methods that a given type provides.
//! For details about how this works in rustc, see the method lookup page in the
//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
use std::sync::Arc;

use arrayvec::ArrayVec;
use rustc_hash::FxHashMap;

use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef};
use crate::{
    db::HirDatabase,
    generics::HasGenericParams,
    impl_block::{ImplBlock, ImplId},
    nameres::CrateModuleId,
    resolve::Resolver,
    ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy},
    ty::{Ty, TypeCtor},
    type_ref::Mutability,
    AssocItem, Crate, Function, Module, Name, Trait,
};

/// This is used as a key for indexing impls.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TyFingerprint {
    Apply(TypeCtor),
}

impl TyFingerprint {
    /// Creates a TyFingerprint for looking up an impl. Only certain types can
    /// have impls: if we have some `struct S`, we can have an `impl S`, but not
    /// `impl &S`. Hence, this will return `None` for reference types and such.
    fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
        match ty {
            Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)),
            _ => None,
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub struct CrateImplBlocks {
    /// To make sense of the CrateModuleIds, we need the source root.
    krate: Crate,
    impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>,
    impls_by_trait: FxHashMap<Trait, Vec<(CrateModuleId, ImplId)>>,
}

impl CrateImplBlocks {
    pub fn lookup_impl_blocks<'a>(&'a self, ty: &Ty) -> impl Iterator<Item = ImplBlock> + 'a {
        let fingerprint = TyFingerprint::for_impl(ty);
        fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                ImplBlock::from_id(module, *impl_id)
            },
        )
    }

    pub fn lookup_impl_blocks_for_trait<'a>(
        &'a self,
        tr: Trait,
    ) -> impl Iterator<Item = ImplBlock> + 'a {
        self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                ImplBlock::from_id(module, *impl_id)
            },
        )
    }

    pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplBlock> + 'a {
        self.impls.values().chain(self.impls_by_trait.values()).flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                ImplBlock::from_id(module, *impl_id)
            },
        )
    }

    fn collect_recursive(&mut self, db: &impl HirDatabase, module: Module) {
        let module_impl_blocks = db.impls_in_module(module);

        for (impl_id, _) in module_impl_blocks.impls.iter() {
            let impl_block = ImplBlock::from_id(module_impl_blocks.module, impl_id);

            let target_ty = impl_block.target_ty(db);

            if impl_block.target_trait(db).is_some() {
                if let Some(tr) = impl_block.target_trait_ref(db) {
                    self.impls_by_trait
                        .entry(tr.trait_)
                        .or_insert_with(Vec::new)
                        .push((module.module_id, impl_id));
                }
            } else {
                if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
                    self.impls
                        .entry(target_ty_fp)
                        .or_insert_with(Vec::new)
                        .push((module.module_id, impl_id));
                }
            }
        }

        for child in module.children(db) {
            self.collect_recursive(db, child);
        }
    }

    pub(crate) fn impls_in_crate_query(
        db: &impl HirDatabase,
        krate: Crate,
    ) -> Arc<CrateImplBlocks> {
        let mut crate_impl_blocks = CrateImplBlocks {
            krate,
            impls: FxHashMap::default(),
            impls_by_trait: FxHashMap::default(),
        };
        if let Some(module) = krate.root_module(db) {
            crate_impl_blocks.collect_recursive(db, module);
        }
        Arc::new(crate_impl_blocks)
    }
}

fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> {
    // Types like slice can have inherent impls in several crates, (core and alloc).
    // The corresponding impls are marked with lang items, so we can use them to find the required crates.
    macro_rules! lang_item_crate {
        ($db:expr, $cur_crate:expr, $($name:expr),+ $(,)?) => {{
            let mut v = ArrayVec::<[Crate; 2]>::new();
            $(
                v.extend($db.lang_item($cur_crate, $name.into()).and_then(|item| item.krate($db)));
            )+
            Some(v)
        }};
    }

    match ty {
        Ty::Apply(a_ty) => match a_ty.ctor {
            TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()),
            TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"),
            TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"),
            TypeCtor::Float(UncertainFloatTy::Known(f)) => match f.bitness {
                // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
                FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"),
                FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"),
            },
            TypeCtor::Int(UncertainIntTy::Known(i)) => {
                lang_item_crate!(db, cur_crate, i.ty_to_string())
            }
            TypeCtor::Str => lang_item_crate!(db, cur_crate, "str_alloc", "str"),
            TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"),
            TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!(db, cur_crate, "const_ptr"),
            TypeCtor::RawPtr(Mutability::Mut) => lang_item_crate!(db, cur_crate, "mut_ptr"),
            _ => None,
        },
        _ => None,
    }
}

/// Look up the method with the given name, returning the actual autoderefed
/// receiver type (but without autoref applied yet).
pub(crate) fn lookup_method(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    name: &Name,
    resolver: &Resolver,
) -> Option<(Ty, Function)> {
    iterate_method_candidates(ty, db, resolver, Some(name), |ty, f| Some((ty.clone(), f)))
}

// This would be nicer if it just returned an iterator, but that runs into
// lifetime problems, because we need to borrow temp `CrateImplBlocks`.
pub(crate) fn iterate_method_candidates<T>(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    resolver: &Resolver,
    name: Option<&Name>,
    mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
    // For method calls, rust first does any number of autoderef, and then one
    // autoref (i.e. when the method takes &self or &mut self). We just ignore
    // the autoref currently -- when we find a method matching the given name,
    // we assume it fits.

    // Also note that when we've got a receiver like &S, even if the method we
    // find in the end takes &self, we still do the autoderef step (just as
    // rustc does an autoderef and then autoref again).

    let krate = resolver.krate()?;
    for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) {
        if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback)
        {
            return Some(result);
        }
        if let Some(result) =
            iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback)
        {
            return Some(result);
        }
    }
    None
}

fn iterate_trait_method_candidates<T>(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    resolver: &Resolver,
    name: Option<&Name>,
    mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
    let krate = resolver.krate()?;
    // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
    let env = lower::trait_env(db, resolver);
    // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope
    let inherent_trait = ty.value.inherent_trait().into_iter();
    // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
    let traits_from_env = env
        .trait_predicates_for_self_ty(&ty.value)
        .map(|tr| tr.trait_)
        .flat_map(|t| t.all_super_traits(db));
    let traits = inherent_trait.chain(traits_from_env).chain(resolver.traits_in_scope(db));
    'traits: for t in traits {
        let data = t.trait_data(db);

        // FIXME this is a bit of a hack, since Chalk should say the same thing
        // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
        let inherently_implemented = ty.value.inherent_trait() == Some(t);

        // we'll be lazy about checking whether the type implements the
        // trait, but if we find out it doesn't, we'll skip the rest of the
        // iteration
        let mut known_implemented = inherently_implemented;
        for item in data.items() {
            if let AssocItem::Function(m) = *item {
                let data = m.data(db);
                if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
                    if !known_implemented {
                        let goal = generic_implements_goal(db, env.clone(), t, ty.clone());
                        if db.trait_solve(krate, goal).is_none() {
                            continue 'traits;
                        }
                    }
                    known_implemented = true;
                    if let Some(result) = callback(&ty.value, m) {
                        return Some(result);
                    }
                }
            }
        }
    }
    None
}

fn iterate_inherent_methods<T>(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    name: Option<&Name>,
    krate: Crate,
    mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
    for krate in def_crates(db, krate, &ty.value)? {
        let impls = db.impls_in_crate(krate);

        for impl_block in impls.lookup_impl_blocks(&ty.value) {
            for item in impl_block.items(db) {
                if let AssocItem::Function(f) = item {
                    let data = f.data(db);
                    if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
                        if let Some(result) = callback(&ty.value, f) {
                            return Some(result);
                        }
                    }
                }
            }
        }
    }
    None
}

pub(crate) fn implements_trait(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    resolver: &Resolver,
    krate: Crate,
    trait_: Trait,
) -> bool {
    if ty.value.inherent_trait() == Some(trait_) {
        // FIXME this is a bit of a hack, since Chalk should say the same thing
        // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
        return true;
    }
    let env = lower::trait_env(db, resolver);
    let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone());
    let solution = db.trait_solve(krate, goal);

    solution.is_some()
}

impl Ty {
    // This would be nicer if it just returned an iterator, but that runs into
    // lifetime problems, because we need to borrow temp `CrateImplBlocks`.
    pub fn iterate_impl_items<T>(
        self,
        db: &impl HirDatabase,
        krate: Crate,
        mut callback: impl FnMut(AssocItem) -> Option<T>,
    ) -> Option<T> {
        for krate in def_crates(db, krate, &self)? {
            let impls = db.impls_in_crate(krate);

            for impl_block in impls.lookup_impl_blocks(&self) {
                for item in impl_block.items(db) {
                    if let Some(result) = callback(item) {
                        return Some(result);
                    }
                }
            }
        }
        None
    }
}

/// This creates Substs for a trait with the given Self type and type variables
/// for all other parameters, to query Chalk with it.
fn generic_implements_goal(
    db: &impl HirDatabase,
    env: Arc<TraitEnvironment>,
    trait_: Trait,
    self_ty: Canonical<Ty>,
) -> Canonical<InEnvironment<super::Obligation>> {
    let mut substs = Vec::new();
    let generics = trait_.generic_params(db);
    let num_vars = self_ty.num_vars;
    substs.push(self_ty.value);
    substs.extend(
        generics
            .params_including_parent()
            .into_iter()
            .skip(1)
            .enumerate()
            .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)),
    );
    let num_vars = substs.len() - 1 + self_ty.num_vars;
    let trait_ref = TraitRef { trait_, substs: substs.into() };
    let obligation = super::Obligation::Trait(trait_ref);
    Canonical { num_vars, value: InEnvironment::new(env, obligation) }
}
<|endoftext|>


<commit_before>use std::{
    convert::TryFrom,
    fmt::{self, Display},
};

use http::Method;

use crate::{error::UnknownVersionError, AuthScheme};

/// Metadata about an API endpoint.
#[derive(Clone, Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct Metadata {
    /// A human-readable description of the endpoint.
    pub description: &'static str,

    /// The HTTP method used by this endpoint.
    pub method: Method,

    /// A unique identifier for this endpoint.
    pub name: &'static str,

    /// (DEPRECATED)
    pub path: &'static str,

    /// The unstable path of this endpoint's URL, often `None`, used for developmental
    /// purposes.
    pub unstable_path: Option<&'static str>,

    /// The pre-v1.1 version of this endpoint's URL, `None` for post-v1.1 endpoints,
    /// supplemental to `stable_path`.
    pub r0_path: Option<&'static str>,

    /// The path of this endpoint's URL, with variable names where path parameters should be
    /// filled in during a request.
    pub stable_path: Option<&'static str>,

    /// Whether or not this endpoint is rate limited by the server.
    pub rate_limited: bool,

    /// What authentication scheme the server uses for this endpoint.
    pub authentication: AuthScheme,

    /// The matrix version that this endpoint was added in.
    ///
    /// Is None when this endpoint is unstable/unreleased.
    pub added: Option<MatrixVersion>,

    /// The matrix version that deprecated this endpoint.
    ///
    /// Deprecation often precedes one matrix version before removal.
    // TODO add once try_into_http_request has been altered;
    // This will make `try_into_http_request` emit a warning,
    // see the corresponding documentation for more information.
    pub deprecated: Option<MatrixVersion>,

    /// The matrix version that removed this endpoint.
    // TODO add once try_into_http_request has been altered;
    // This will make `try_into_http_request` emit an error,
    // see the corresponding documentation for more information.
    pub removed: Option<MatrixVersion>,
}

/// The Matrix versions Ruma currently understands to exist.
///
/// Matrix, since fall 2021, has a quarterly release schedule, using a global `vX.Y` versioning
/// scheme.
///
/// Every new minor version denotes stable support for endpoints in a *relatively*
/// backwards-compatible manner.
///
/// Matrix has a deprecation policy, read more about it here: <https://spec.matrix.org/v1.2/#deprecation-policy>.
// TODO add the following once `EndpointPath` and added/deprecated/removed macros are in place;
// Ruma keeps track of when endpoints are added, deprecated, and removed. It'll automatically
// select the right endpoint stability variation to use depending on which Matrix version you
// pass it with [`EndpointPath`], see its respective documentation for more.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum MatrixVersion {
    /// Version 1.0 of the Matrix specification.
    ///
    /// Retroactively defined as <https://spec.matrix.org/v1.1/#legacy-versioning>.
    V1_0,

    /// Version 1.1 of the Matrix specification, released in Q4 2021.
    ///
    /// See <https://spec.matrix.org/v1.1/>.
    V1_1,

    /// Version 1.2 of the Matrix specification, released in Q1 2022.
    ///
    /// See <https://spec.matrix.org/v1.2/>.
    V1_2,
}

impl TryFrom<&str> for MatrixVersion {
    type Error = UnknownVersionError;

    fn try_from(value: &str) -> Result<MatrixVersion, Self::Error> {
        use MatrixVersion::*;

        Ok(match value {
            // FIXME: these are likely not entirely correct; https://github.com/ruma/ruma/issues/852
            "v1.0" |
            // Additional definitions according to https://spec.matrix.org/v1.2/#legacy-versioning
            "r0.5.0" | "r0.6.0" | "r0.6.1" => V1_0,
            "v1.1" => V1_1,
            "v1.2" => V1_2,
            _ => return Err(UnknownVersionError),
        })
    }
}

impl MatrixVersion {
    /// Checks whether a version is compatible with another.
    ///
    /// A is compatible with B as long as B is equal or less, so long as A and B have the same
    /// major versions.
    ///
    /// For example, v1.2 is compatible with v1.1, as it is likely only some additions of
    /// endpoints on top of v1.1, but v1.1 would not be compatible with v1.2, as v1.1
    /// cannot represent all of v1.2, in a manner similar to set theory.
    ///
    /// Warning: Matrix has a deprecation policy, and Matrix versioning is not as
    /// straight-forward as this function makes it out to be. This function only exists
    /// to prune major version differences, and versions too new for `self`.
    ///
    /// This (considering if major versions are the same) is equivalent to a `self >= other`
    /// check.
    pub fn is_superset_of(self, other: Self) -> bool {
        let (major_l, minor_l) = self.into_parts();
        let (major_r, minor_r) = other.into_parts();
        major_l == major_r && minor_l >= minor_r
    }

    /// Decompose the Matrix version into its major and minor number.
    pub fn into_parts(self) -> (u8, u8) {
        match self {
            MatrixVersion::V1_0 => (1, 0),
            MatrixVersion::V1_1 => (1, 1),
            MatrixVersion::V1_2 => (1, 2),
        }
    }

    /// Try to turn a pair of (major, minor) version components back into a `MatrixVersion`.
    pub fn from_parts(major: u8, minor: u8) -> Result<Self, UnknownVersionError> {
        match (major, minor) {
            (1, 0) => Ok(MatrixVersion::V1_0),
            (1, 1) => Ok(MatrixVersion::V1_1),
            (1, 2) => Ok(MatrixVersion::V1_2),
            _ => Err(UnknownVersionError),
        }
    }
}

impl Display for MatrixVersion {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let (major, minor) = self.into_parts();
        f.write_str(&format!("v{}.{}", major, minor))
    }
}
<commit_msg>api: Add impl FromStr for MatrixVersion<commit_after>use std::{
    convert::TryFrom,
    fmt::{self, Display},
    str::FromStr,
};

use http::Method;

use crate::{error::UnknownVersionError, AuthScheme};

/// Metadata about an API endpoint.
#[derive(Clone, Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct Metadata {
    /// A human-readable description of the endpoint.
    pub description: &'static str,

    /// The HTTP method used by this endpoint.
    pub method: Method,

    /// A unique identifier for this endpoint.
    pub name: &'static str,

    /// (DEPRECATED)
    pub path: &'static str,

    /// The unstable path of this endpoint's URL, often `None`, used for developmental
    /// purposes.
    pub unstable_path: Option<&'static str>,

    /// The pre-v1.1 version of this endpoint's URL, `None` for post-v1.1 endpoints,
    /// supplemental to `stable_path`.
    pub r0_path: Option<&'static str>,

    /// The path of this endpoint's URL, with variable names where path parameters should be
    /// filled in during a request.
    pub stable_path: Option<&'static str>,

    /// Whether or not this endpoint is rate limited by the server.
    pub rate_limited: bool,

    /// What authentication scheme the server uses for this endpoint.
    pub authentication: AuthScheme,

    /// The matrix version that this endpoint was added in.
    ///
    /// Is None when this endpoint is unstable/unreleased.
    pub added: Option<MatrixVersion>,

    /// The matrix version that deprecated this endpoint.
    ///
    /// Deprecation often precedes one matrix version before removal.
    // TODO add once try_into_http_request has been altered;
    // This will make `try_into_http_request` emit a warning,
    // see the corresponding documentation for more information.
    pub deprecated: Option<MatrixVersion>,

    /// The matrix version that removed this endpoint.
    // TODO add once try_into_http_request has been altered;
    // This will make `try_into_http_request` emit an error,
    // see the corresponding documentation for more information.
    pub removed: Option<MatrixVersion>,
}

/// The Matrix versions Ruma currently understands to exist.
///
/// Matrix, since fall 2021, has a quarterly release schedule, using a global `vX.Y` versioning
/// scheme.
///
/// Every new minor version denotes stable support for endpoints in a *relatively*
/// backwards-compatible manner.
///
/// Matrix has a deprecation policy, read more about it here: <https://spec.matrix.org/v1.2/#deprecation-policy>.
// TODO add the following once `EndpointPath` and added/deprecated/removed macros are in place;
// Ruma keeps track of when endpoints are added, deprecated, and removed. It'll automatically
// select the right endpoint stability variation to use depending on which Matrix version you
// pass it with [`EndpointPath`], see its respective documentation for more.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum MatrixVersion {
    /// Version 1.0 of the Matrix specification.
    ///
    /// Retroactively defined as <https://spec.matrix.org/v1.1/#legacy-versioning>.
    V1_0,

    /// Version 1.1 of the Matrix specification, released in Q4 2021.
    ///
    /// See <https://spec.matrix.org/v1.1/>.
    V1_1,

    /// Version 1.2 of the Matrix specification, released in Q1 2022.
    ///
    /// See <https://spec.matrix.org/v1.2/>.
    V1_2,
}

impl TryFrom<&str> for MatrixVersion {
    type Error = UnknownVersionError;

    fn try_from(value: &str) -> Result<MatrixVersion, Self::Error> {
        use MatrixVersion::*;

        Ok(match value {
            // FIXME: these are likely not entirely correct; https://github.com/ruma/ruma/issues/852
            "v1.0" |
            // Additional definitions according to https://spec.matrix.org/v1.2/#legacy-versioning
            "r0.5.0" | "r0.6.0" | "r0.6.1" => V1_0,
            "v1.1" => V1_1,
            "v1.2" => V1_2,
            _ => return Err(UnknownVersionError),
        })
    }
}

impl FromStr for MatrixVersion {
    type Err = UnknownVersionError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::try_from(s)
    }
}

impl MatrixVersion {
    /// Checks whether a version is compatible with another.
    ///
    /// A is compatible with B as long as B is equal or less, so long as A and B have the same
    /// major versions.
    ///
    /// For example, v1.2 is compatible with v1.1, as it is likely only some additions of
    /// endpoints on top of v1.1, but v1.1 would not be compatible with v1.2, as v1.1
    /// cannot represent all of v1.2, in a manner similar to set theory.
    ///
    /// Warning: Matrix has a deprecation policy, and Matrix versioning is not as
    /// straight-forward as this function makes it out to be. This function only exists
    /// to prune major version differences, and versions too new for `self`.
    ///
    /// This (considering if major versions are the same) is equivalent to a `self >= other`
    /// check.
    pub fn is_superset_of(self, other: Self) -> bool {
        let (major_l, minor_l) = self.into_parts();
        let (major_r, minor_r) = other.into_parts();
        major_l == major_r && minor_l >= minor_r
    }

    /// Decompose the Matrix version into its major and minor number.
    pub fn into_parts(self) -> (u8, u8) {
        match self {
            MatrixVersion::V1_0 => (1, 0),
            MatrixVersion::V1_1 => (1, 1),
            MatrixVersion::V1_2 => (1, 2),
        }
    }

    /// Try to turn a pair of (major, minor) version components back into a `MatrixVersion`.
    pub fn from_parts(major: u8, minor: u8) -> Result<Self, UnknownVersionError> {
        match (major, minor) {
            (1, 0) => Ok(MatrixVersion::V1_0),
            (1, 1) => Ok(MatrixVersion::V1_1),
            (1, 2) => Ok(MatrixVersion::V1_2),
            _ => Err(UnknownVersionError),
        }
    }
}

impl Display for MatrixVersion {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let (major, minor) = self.into_parts();
        f.write_str(&format!("v{}.{}", major, minor))
    }
}
<|endoftext|>


<commit_before>use super::behaviors::{MouseBehavior, SelectionBehavior};
use crate::prelude::*;

widget!(
    /// The `CheckBox` widget can be switch its selected state. It contains a selection box and a text.
    ///
    /// **CSS element:** `check-box`
    CheckBox: MouseHandler,
    ChangedHandler {
	/// Sets or shares the background property.
	background: Brush,

	/// Sets or shares the border radius property.
	border_radius: f64,

	/// Sets or shares the border thickness property.
	border_width: Thickness,

	/// Sets or shares the border brush property.
	border_brush: Brush,

	/// Sets or shares the padding property.
	padding: Thickness,

	/// Sets or shares the foreground property.
	foreground: Brush,

	/// Sets or shares the text property.
	text: String16,

	/// Sets or share the font size property.
	font_size: f64,

	/// Sets or shares the font property.
	font: String,

	/// Sets or shares the icon property.
	icon: String,

	/// Sets or shares the icon brush property.
	icon_brush: Brush,

	/// Sets or share the icon font size property.
	icon_size: f64,

	/// Sets or shares the icon font property.
	icon_font: String,

	/// Sets or shares the pressed property.
	pressed: bool,

	/// Sets or shares the selected property.
	selected: bool
    }
);

impl Template for CheckBox {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
	self.name("CheckBox")
	    .element("check-box")
	    .selected(false)
	    .height(24.0)
	    .background(colors::LYNCH_COLOR)
	    .border_radius(2.0)
	    .border_width(0.0)
	    .border_brush("transparent")
	    .padding((8.0, 0.0, 8.0, 0.0))
	    .foreground(colors::LINK_WATER_COLOR)
	    .text("")
	    .font_size(fonts::FONT_SIZE_12)
	    .font("Roboto Regular")
	    .icon(material_icons_font_ttf::CHECK_FONT_ICON)
	    .icon_font("Material Icons")
	    .icon_size(fonts::ICON_FONT_SIZE_12)
	    .icon_brush(colors::LINK_WATER_COLOR)
	    .pressed(false)
	    .child(
		MouseBehavior::new()
		    .pressed(id)
		    .enabled(id)
		    .target(id.0)
		    .child(
			SelectionBehavior::new()
			    .selected(id)
			    .enabled(id)
			    .target(id.0)
			    .child(
				Stack::new()
				    .orientation("horizontal")
				    .spacing(8.0)
				    .child(
					Container::new()
					    .size(24.0, 24.0)
					    .background(id)
					    .border_radius(id)
					    .border_width(id)
					    .border_brush(id)
					    .padding(id)
					    .opacity(id)
					    .child(
						FontIconBlock::new()
						    .v_align("center")
						    .h_align("center")
						    .icon(id)
						    .icon_brush(id)
						    .icon_size(id)
						    .icon_font(id)
						    .opacity(id)
						    .build(ctx),
					    )
					    .build(ctx),
				    )
				    .child(
					TextBlock::new()
					    .v_align("center")
					    .foreground(id)
					    .text(id)
					    .font_size(id)
					    .font(id)
					    .opacity(id)
					    .build(ctx),
				    )
				    .build(ctx),
			    )
			    .build(ctx),
		    )
		    .build(ctx),
	    )
    }
}
<commit_msg>widgets: checkbox.rs update<commit_after>use super::behaviors::{MouseBehavior, SelectionBehavior};
use crate::prelude::*;

widget!(
    /// The `CheckBox` widget can be switch its selected state. It contains a selection box and a text.
    ///
    /// **CSS element:** `check-box`
    CheckBox: MouseHandler,
    ChangedHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or shares the text property.
        text: String16,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the icon property.
        icon: String,

        /// Sets or shares the icon brush property.
        icon_brush: Brush,

        /// Sets or share the icon font size property.
        icon_size: f64,

        /// Sets or shares the icon font property.
        icon_font: String,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the selected property.
        selected: bool
    }
);

impl Template for CheckBox {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("CheckBox")
            .element("check-box")
            .selected(false)
            .height(24.0)
            .background(colors::LYNCH_COLOR)
            .border_radius(2.0)
            .border_width(0.0)
            .border_brush("transparent")
            .padding((8.0, 0.0, 8.0, 0.0))
            .foreground(colors::LINK_WATER_COLOR)
            .text("")
            .font_size(fonts::FONT_SIZE_12)
            .font("Roboto Regular")
            .icon(material_icons_font_ttf::MD_CHECK)
            .icon_font("Material Icons")
            .icon_size(fonts::ICON_FONT_SIZE_12)
            .icon_brush(colors::LINK_WATER_COLOR)
            .pressed(false)
            .child(
                MouseBehavior::new()
                    .pressed(id)
                    .enabled(id)
                    .target(id.0)
                    .child(
                        SelectionBehavior::new()
                            .selected(id)
                            .enabled(id)
                            .target(id.0)
                            .child(
                                Stack::new()
                                    .orientation("horizontal")
                                    .spacing(8.0)
                                    .child(
                                        Container::new()
                                            .size(24.0, 24.0)
                                            .background(id)
                                            .border_radius(id)
                                            .border_width(id)
                                            .border_brush(id)
                                            .padding(id)
                                            .opacity(id)
                                            .child(
                                                FontIconBlock::new()
                                                    .v_align("center")
                                                    .h_align("center")
                                                    .icon(id)
                                                    .icon_brush(id)
                                                    .icon_size(id)
                                                    .icon_font(id)
                                                    .opacity(id)
                                                    .build(ctx),
                                            )
                                            .build(ctx),
                                    )
                                    .child(
                                        TextBlock::new()
                                            .v_align("center")
                                            .foreground(id)
                                            .text(id)
                                            .font_size(id)
                                            .font(id)
                                            .opacity(id)
                                            .build(ctx),
                                    )
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .build(ctx),
            )
    }
}
<|endoftext|>