<commit_before>mod cpu_features;

pub use self::cpu_features::{CpuFeatures, SpecificFeature, TargetCpu};
use crate::decls::ModuleDecls;
use crate::error::Error;
use crate::function::FuncInfo;
use crate::heap::HeapSettings;
use crate::module::ModuleInfo;
use crate::output::{CraneliftFuncs, ObjectFile};
use crate::runtime::Runtime;
use crate::stack_probe;
use crate::table::write_table_data;
use cranelift_codegen::{
    ir,
    isa::TargetIsa,
    settings::{self, Configurable},
    Context as ClifContext,
};
use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieTrapCollection};
use cranelift_module::{Backend as ClifBackend, Module as ClifModule};
use cranelift_wasm::{translate_module, FuncTranslator, ModuleTranslationState, WasmError};
use lucet_module::bindings::Bindings;
use lucet_module::{FunctionSpec, ModuleData, ModuleFeatures, MODULE_DATA_SYM};
use lucet_validate::Validator;
use target_lexicon::Triple;

#[derive(Debug, Clone, Copy)]
pub enum OptLevel {
    None,
    Speed,
    SpeedAndSize,
}

impl Default for OptLevel {
    fn default() -> OptLevel {
        OptLevel::SpeedAndSize
    }
}

impl OptLevel {
    pub fn to_flag(&self) -> &str {
        match self {
            OptLevel::None => "none",
            OptLevel::Speed => "speed",
            OptLevel::SpeedAndSize => "speed_and_size",
        }
    }
}

pub struct Compiler<'a> {
    decls: ModuleDecls<'a>,
    clif_module: ClifModule<FaerieBackend>,
    target: Triple,
    opt_level: OptLevel,
    cpu_features: CpuFeatures,
    count_instructions: bool,
    module_translation_state: ModuleTranslationState,
    canonicalize_nans: bool,
}

impl<'a> Compiler<'a> {
    pub fn new(
        wasm_binary: &'a [u8],
        target: Triple,
        opt_level: OptLevel,
        cpu_features: CpuFeatures,
        bindings: &'a Bindings,
        heap_settings: HeapSettings,
        count_instructions: bool,
        validator: &Option<Validator>,
        canonicalize_nans: bool,
    ) -> Result<Self, Error> {
        let isa = Self::target_isa(target.clone(), opt_level, &cpu_features, canonicalize_nans)?;

        let frontend_config = isa.frontend_config();
        let mut module_info = ModuleInfo::new(frontend_config.clone());

        if let Some(v) = validator {
            v.validate(wasm_binary).map_err(Error::LucetValidation)?;
        } else {
            // As of cranelift-wasm 0.43 which uses wasmparser 0.39.1, the parser used inside
            // cranelift-wasm does not validate. We need to run the validating parser on the binary
            // first. The InvalidWebAssembly error below will never trigger.
            wasmparser::validate(wasm_binary, None).map_err(Error::WasmValidation)?;
        }

        let module_translation_state =
            translate_module(wasm_binary, &mut module_info).map_err(|e| match e {
                WasmError::User(u) => Error::Input(u),
                WasmError::InvalidWebAssembly { .. } => {
                    // Since wasmparser was already used to validate,
                    // reaching this case means there's a significant
                    // bug in either wasmparser or cranelift-wasm.
                    unreachable!();
                }
                WasmError::Unsupported(s) => Error::Unsupported(s),
                WasmError::ImplLimitExceeded { .. } => Error::ClifWasmError(e),
            })?;

        let libcalls = Box::new(move |libcall| match libcall {
            ir::LibCall::Probestack => stack_probe::STACK_PROBE_SYM.to_owned(),
            _ => (cranelift_module::default_libcall_names())(libcall),
        });

        let mut clif_module: ClifModule<FaerieBackend> = ClifModule::new(FaerieBuilder::new(
            isa,
            "lucet_guest".to_owned(),
            FaerieTrapCollection::Enabled,
            libcalls,
        )?);

        let runtime = Runtime::lucet(frontend_config);
        let decls = ModuleDecls::new(
            module_info,
            &mut clif_module,
            bindings,
            runtime,
            heap_settings,
        )?;

        Ok(Self {
            decls,
            clif_module,
            opt_level,
            cpu_features,
            count_instructions,
            module_translation_state,
            target,
            canonicalize_nans,
        })
    }

    pub fn module_features(&self) -> ModuleFeatures {
        let mut mf: ModuleFeatures = (&self.cpu_features).into();
        mf.instruction_count = self.count_instructions;
        mf
    }

    pub fn module_data(&self) -> Result<ModuleData<'_>, Error> {
        self.decls.get_module_data(self.module_features())
    }

    pub fn object_file(mut self) -> Result<ObjectFile, Error> {
        let mut func_translator = FuncTranslator::new();

        for (ref func, (code, code_offset)) in self.decls.function_bodies() {
            let mut func_info = FuncInfo::new(&self.decls, self.count_instructions);
            let mut clif_context = ClifContext::new();
            clif_context.func.name = func.name.as_externalname();
            clif_context.func.signature = func.signature.clone();

            func_translator
                .translate(
                    &self.module_translation_state,
                    code,
                    *code_offset,
                    &mut clif_context.func,
                    &mut func_info,
                )
                .map_err(|source| Error::FunctionTranslation {
                    symbol: func.name.symbol().to_string(),
                    source,
                })?;
            self.clif_module
                .define_function(func.name.as_funcid().unwrap(), &mut clif_context)
                .map_err(|source| Error::FunctionDefinition {
                    symbol: func.name.symbol().to_string(),
                    source,
                })?;
        }

        stack_probe::declare_metadata(&mut self.decls, &mut self.clif_module).unwrap();

        let module_data_bytes = self.module_data()?.serialize()?;

        let module_data_len = module_data_bytes.len();

        write_module_data(&mut self.clif_module, module_data_bytes)?;
        write_startfunc_data(&mut self.clif_module, &self.decls)?;
        let table_len = write_table_data(&mut self.clif_module, &self.decls)?;

        let function_manifest: Vec<(String, FunctionSpec)> = self
            .clif_module
            .declared_functions()
            .map(|f| {
                (
                    f.decl.name.to_owned(), // this copy is only necessary because `clif_module` is moved in `finish, below`
                    FunctionSpec::new(
                        0,
                        f.compiled.as_ref().map(|c| c.code_length()).unwrap_or(0),
                        0,
                        0,
                    ),
                )
            })
            .collect();

        let obj = ObjectFile::new(
            self.clif_module.finish(),
            module_data_len,
            function_manifest,
            table_len,
        )?;

        Ok(obj)
    }

    pub fn cranelift_funcs(self) -> Result<CraneliftFuncs, Error> {
        use std::collections::HashMap;

        let mut funcs = HashMap::new();
        let mut func_translator = FuncTranslator::new();

        for (ref func, (code, code_offset)) in self.decls.function_bodies() {
            let mut func_info = FuncInfo::new(&self.decls, self.count_instructions);
            let mut clif_context = ClifContext::new();
            clif_context.func.name = func.name.as_externalname();
            clif_context.func.signature = func.signature.clone();

            func_translator
                .translate(
                    &self.module_translation_state,
                    code,
                    *code_offset,
                    &mut clif_context.func,
                    &mut func_info,
                )
                .map_err(|source| Error::FunctionTranslation {
                    symbol: func.name.symbol().to_string(),
                    source,
                })?;

            funcs.insert(func.name.clone(), clif_context.func);
        }
        Ok(CraneliftFuncs::new(
            funcs,
            Self::target_isa(
                self.target,
                self.opt_level,
                &self.cpu_features,
                self.canonicalize_nans,
            )?,
        ))
    }

    fn target_isa(
        target: Triple,
        opt_level: OptLevel,
        cpu_features: &CpuFeatures,
        canonicalize_nans: bool,
    ) -> Result<Box<dyn TargetIsa>, Error> {
        let mut flags_builder = settings::builder();
        let isa_builder = cpu_features.isa_builder(target)?;
        flags_builder.enable("enable_verifier").unwrap();
        flags_builder.enable("is_pic").unwrap();
        flags_builder.set("opt_level", opt_level.to_flag()).unwrap();
        if canonicalize_nans {
            flags_builder.enable("enable_nan_canonicalization").unwrap();
        }
        Ok(isa_builder.finish(settings::Flags::new(flags_builder)))
    }
}

fn write_module_data<B: ClifBackend>(
    clif_module: &mut ClifModule<B>,
    module_data_bytes: Vec<u8>,
) -> Result<(), Error> {
    use cranelift_module::{DataContext, Linkage};

    let mut module_data_ctx = DataContext::new();
    module_data_ctx.define(module_data_bytes.into_boxed_slice());

    let module_data_decl = clif_module
        .declare_data(MODULE_DATA_SYM, Linkage::Local, true, None)
        .map_err(Error::ClifModuleError)?;
    clif_module
        .define_data(module_data_decl, &module_data_ctx)
        .map_err(Error::ClifModuleError)?;

    Ok(())
}

fn write_startfunc_data<B: ClifBackend>(
    clif_module: &mut ClifModule<B>,
    decls: &ModuleDecls<'_>,
) -> Result<(), Error> {
    use cranelift_module::{DataContext, Linkage};

    if let Some(func_ix) = decls.get_start_func() {
        let name = clif_module
            .declare_data("guest_start", Linkage::Export, false, None)
            .map_err(Error::MetadataSerializer)?;
        let mut ctx = DataContext::new();
        ctx.define_zeroinit(8);

        let start_func = decls
            .get_func(func_ix)
            .expect("start func is valid func id");
        let fid = start_func.name.as_funcid().expect("start func is a func");
        let fref = clif_module.declare_func_in_data(fid, &mut ctx);
        ctx.write_function_addr(0, fref);
        clif_module
            .define_data(name, &ctx)
            .map_err(Error::MetadataSerializer)?;
    }
    Ok(())
}
<commit_msg>lucetc: don't use define_zeroinit for guest_start data<commit_after>mod cpu_features;

pub use self::cpu_features::{CpuFeatures, SpecificFeature, TargetCpu};
use crate::decls::ModuleDecls;
use crate::error::Error;
use crate::function::FuncInfo;
use crate::heap::HeapSettings;
use crate::module::ModuleInfo;
use crate::output::{CraneliftFuncs, ObjectFile};
use crate::runtime::Runtime;
use crate::stack_probe;
use crate::table::write_table_data;
use cranelift_codegen::{
    ir,
    isa::TargetIsa,
    settings::{self, Configurable},
    Context as ClifContext,
};
use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieTrapCollection};
use cranelift_module::{Backend as ClifBackend, Module as ClifModule};
use cranelift_wasm::{translate_module, FuncTranslator, ModuleTranslationState, WasmError};
use lucet_module::bindings::Bindings;
use lucet_module::{FunctionSpec, ModuleData, ModuleFeatures, MODULE_DATA_SYM};
use lucet_validate::Validator;
use target_lexicon::Triple;

#[derive(Debug, Clone, Copy)]
pub enum OptLevel {
    None,
    Speed,
    SpeedAndSize,
}

impl Default for OptLevel {
    fn default() -> OptLevel {
        OptLevel::SpeedAndSize
    }
}

impl OptLevel {
    pub fn to_flag(&self) -> &str {
        match self {
            OptLevel::None => "none",
            OptLevel::Speed => "speed",
            OptLevel::SpeedAndSize => "speed_and_size",
        }
    }
}

pub struct Compiler<'a> {
    decls: ModuleDecls<'a>,
    clif_module: ClifModule<FaerieBackend>,
    target: Triple,
    opt_level: OptLevel,
    cpu_features: CpuFeatures,
    count_instructions: bool,
    module_translation_state: ModuleTranslationState,
    canonicalize_nans: bool,
}

impl<'a> Compiler<'a> {
    pub fn new(
        wasm_binary: &'a [u8],
        target: Triple,
        opt_level: OptLevel,
        cpu_features: CpuFeatures,
        bindings: &'a Bindings,
        heap_settings: HeapSettings,
        count_instructions: bool,
        validator: &Option<Validator>,
        canonicalize_nans: bool,
    ) -> Result<Self, Error> {
        let isa = Self::target_isa(target.clone(), opt_level, &cpu_features, canonicalize_nans)?;

        let frontend_config = isa.frontend_config();
        let mut module_info = ModuleInfo::new(frontend_config.clone());

        if let Some(v) = validator {
            v.validate(wasm_binary).map_err(Error::LucetValidation)?;
        } else {
            // As of cranelift-wasm 0.43 which uses wasmparser 0.39.1, the parser used inside
            // cranelift-wasm does not validate. We need to run the validating parser on the binary
            // first. The InvalidWebAssembly error below will never trigger.
            wasmparser::validate(wasm_binary, None).map_err(Error::WasmValidation)?;
        }

        let module_translation_state =
            translate_module(wasm_binary, &mut module_info).map_err(|e| match e {
                WasmError::User(u) => Error::Input(u),
                WasmError::InvalidWebAssembly { .. } => {
                    // Since wasmparser was already used to validate,
                    // reaching this case means there's a significant
                    // bug in either wasmparser or cranelift-wasm.
                    unreachable!();
                }
                WasmError::Unsupported(s) => Error::Unsupported(s),
                WasmError::ImplLimitExceeded { .. } => Error::ClifWasmError(e),
            })?;

        let libcalls = Box::new(move |libcall| match libcall {
            ir::LibCall::Probestack => stack_probe::STACK_PROBE_SYM.to_owned(),
            _ => (cranelift_module::default_libcall_names())(libcall),
        });

        let mut clif_module: ClifModule<FaerieBackend> = ClifModule::new(FaerieBuilder::new(
            isa,
            "lucet_guest".to_owned(),
            FaerieTrapCollection::Enabled,
            libcalls,
        )?);

        let runtime = Runtime::lucet(frontend_config);
        let decls = ModuleDecls::new(
            module_info,
            &mut clif_module,
            bindings,
            runtime,
            heap_settings,
        )?;

        Ok(Self {
            decls,
            clif_module,
            opt_level,
            cpu_features,
            count_instructions,
            module_translation_state,
            target,
            canonicalize_nans,
        })
    }

    pub fn module_features(&self) -> ModuleFeatures {
        let mut mf: ModuleFeatures = (&self.cpu_features).into();
        mf.instruction_count = self.count_instructions;
        mf
    }

    pub fn module_data(&self) -> Result<ModuleData<'_>, Error> {
        self.decls.get_module_data(self.module_features())
    }

    pub fn object_file(mut self) -> Result<ObjectFile, Error> {
        let mut func_translator = FuncTranslator::new();

        for (ref func, (code, code_offset)) in self.decls.function_bodies() {
            let mut func_info = FuncInfo::new(&self.decls, self.count_instructions);
            let mut clif_context = ClifContext::new();
            clif_context.func.name = func.name.as_externalname();
            clif_context.func.signature = func.signature.clone();

            func_translator
                .translate(
                    &self.module_translation_state,
                    code,
                    *code_offset,
                    &mut clif_context.func,
                    &mut func_info,
                )
                .map_err(|source| Error::FunctionTranslation {
                    symbol: func.name.symbol().to_string(),
                    source,
                })?;
            self.clif_module
                .define_function(func.name.as_funcid().unwrap(), &mut clif_context)
                .map_err(|source| Error::FunctionDefinition {
                    symbol: func.name.symbol().to_string(),
                    source,
                })?;
        }

        stack_probe::declare_metadata(&mut self.decls, &mut self.clif_module).unwrap();

        let module_data_bytes = self.module_data()?.serialize()?;

        let module_data_len = module_data_bytes.len();

        write_module_data(&mut self.clif_module, module_data_bytes)?;
        write_startfunc_data(&mut self.clif_module, &self.decls)?;
        let table_len = write_table_data(&mut self.clif_module, &self.decls)?;

        let function_manifest: Vec<(String, FunctionSpec)> = self
            .clif_module
            .declared_functions()
            .map(|f| {
                (
                    f.decl.name.to_owned(), // this copy is only necessary because `clif_module` is moved in `finish, below`
                    FunctionSpec::new(
                        0,
                        f.compiled.as_ref().map(|c| c.code_length()).unwrap_or(0),
                        0,
                        0,
                    ),
                )
            })
            .collect();

        let obj = ObjectFile::new(
            self.clif_module.finish(),
            module_data_len,
            function_manifest,
            table_len,
        )?;

        Ok(obj)
    }

    pub fn cranelift_funcs(self) -> Result<CraneliftFuncs, Error> {
        use std::collections::HashMap;

        let mut funcs = HashMap::new();
        let mut func_translator = FuncTranslator::new();

        for (ref func, (code, code_offset)) in self.decls.function_bodies() {
            let mut func_info = FuncInfo::new(&self.decls, self.count_instructions);
            let mut clif_context = ClifContext::new();
            clif_context.func.name = func.name.as_externalname();
            clif_context.func.signature = func.signature.clone();

            func_translator
                .translate(
                    &self.module_translation_state,
                    code,
                    *code_offset,
                    &mut clif_context.func,
                    &mut func_info,
                )
                .map_err(|source| Error::FunctionTranslation {
                    symbol: func.name.symbol().to_string(),
                    source,
                })?;

            funcs.insert(func.name.clone(), clif_context.func);
        }
        Ok(CraneliftFuncs::new(
            funcs,
            Self::target_isa(
                self.target,
                self.opt_level,
                &self.cpu_features,
                self.canonicalize_nans,
            )?,
        ))
    }

    fn target_isa(
        target: Triple,
        opt_level: OptLevel,
        cpu_features: &CpuFeatures,
        canonicalize_nans: bool,
    ) -> Result<Box<dyn TargetIsa>, Error> {
        let mut flags_builder = settings::builder();
        let isa_builder = cpu_features.isa_builder(target)?;
        flags_builder.enable("enable_verifier").unwrap();
        flags_builder.enable("is_pic").unwrap();
        flags_builder.set("opt_level", opt_level.to_flag()).unwrap();
        if canonicalize_nans {
            flags_builder.enable("enable_nan_canonicalization").unwrap();
        }
        Ok(isa_builder.finish(settings::Flags::new(flags_builder)))
    }
}

fn write_module_data<B: ClifBackend>(
    clif_module: &mut ClifModule<B>,
    module_data_bytes: Vec<u8>,
) -> Result<(), Error> {
    use cranelift_module::{DataContext, Linkage};

    let mut module_data_ctx = DataContext::new();
    module_data_ctx.define(module_data_bytes.into_boxed_slice());

    let module_data_decl = clif_module
        .declare_data(MODULE_DATA_SYM, Linkage::Local, true, None)
        .map_err(Error::ClifModuleError)?;
    clif_module
        .define_data(module_data_decl, &module_data_ctx)
        .map_err(Error::ClifModuleError)?;

    Ok(())
}

fn write_startfunc_data<B: ClifBackend>(
    clif_module: &mut ClifModule<B>,
    decls: &ModuleDecls<'_>,
) -> Result<(), Error> {
    use cranelift_module::{DataContext, Linkage};

    if let Some(func_ix) = decls.get_start_func() {
        let name = clif_module
            .declare_data("guest_start", Linkage::Export, false, None)
            .map_err(Error::MetadataSerializer)?;
        let mut ctx = DataContext::new();
        ctx.define(vec![0u8; 8].into_boxed_slice());

        let start_func = decls
            .get_func(func_ix)
            .expect("start func is valid func id");
        let fid = start_func.name.as_funcid().expect("start func is a func");
        let fref = clif_module.declare_func_in_data(fid, &mut ctx);
        ctx.write_function_addr(0, fref);
        clif_module
            .define_data(name, &ctx)
            .map_err(Error::MetadataSerializer)?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::f32;
use std::u32;

use crate::utils::*;
use crate::graph::*;
use crate::sim::{Io, TestPacket, RoutingAlgorithm};

/*
fn get_local_error(pos: Vec3, neighbors: &Vec<Neighbor>) -> f32 {
	/*
	let mut mean = Vec3::new0();
	for v in neighbors {
		mean += v.pos;
	}

	pos.distance(&mean)
	*/
	1.0
}*/

#[derive(Clone)]
struct Neighbor {
	id: ID,
	pos: Vec3,
	error: f32,
	last_updated: u32
}

impl PartialEq for Neighbor {
	fn eq(&self, other: &Neighbor) -> bool {
		self.id == other.id
	}
}

#[derive(Clone)]
struct Node {
	pos: Vec3,
	error: f32,
	pos_old: Vec3,
	neighbors: Vec<Neighbor>,
}

impl Node {
	fn new() -> Self {
		Self {
			pos: Vec3::new0(),
			error: 0.0,
			pos_old: Vec3::new0(),
			neighbors: vec![],
		}
	}

	fn reset(&mut self) {
		self.pos = Vec3::new0();
		self.error = 0.0;
		self.pos_old = Vec3::new0();
		self.neighbors.clear();
	}

	fn timeout_entries(&mut self, time: u32) {
		vec_filter(&mut self.neighbors, |ref e| (e.last_updated + 5) >= time);
	}

	fn route(&self, packet: &TestPacket, dst_pos: &Vec3) -> Option<ID> {
		let mut d_next = f32::INFINITY;
		let mut n_next = None;

		for v in &self.neighbors {
			let d = v.pos.distance(dst_pos);
			if d < d_next {
				d_next = d;
				n_next = Some(v.id);
			}
		}

		n_next
	}

	fn update(&mut self, from_id: ID, from_pos: Vec3, from_error: f32, time: u32, rtt: f32) {
		vec_add_entry(&mut self.neighbors,
			&Neighbor {
				id: from_id,
				pos: from_pos,
				error: from_error,
				last_updated: time
			}
		);

		self.vivaldi_update(&from_pos, from_error, rtt);
	}

	// Vivaldi algorithm
	fn vivaldi_update(&mut self, pos: &Vec3, error: f32, rtt: f32) {
		//let rtt = self.rtt;
		let ce = 0.25;
		let cc = 0.25;

		// w = e_i / (e_i + e_j)
		let w = if (self.error > 0.0) && (error > 0.0) {
			self.error / (self.error + error)
		} else {
			1.0
		};

		// x_i - x_j
		let ab = self.pos - *pos;

		// rtt - |x_i - x_j|
		let re = rtt - ab.length();

		// e_s = ||x_i - x_j| - rtt| / rtt
		let es = re.abs() / rtt;

		// e_i = e_s * c_e * w + e_i * (1 - c_e * w)
		self.error = es * ce * w + self.error * (1.0 - ce * w);

		// ∂ = c_c * w
		let d = cc * w;

		// Choose random direction if both positions are identical
		let direction = if ab.is_near_null(0.01) {
			//println!("random direction");
			Vec3::random_unit()
		} else {
			ab
		};

		//println!("old pos: {}, {} {} {}", self.pos, direction, w, re);

		// x_i = x_i + ∂ * (rtt - |x_i - x_j|) * u(x_i - x_j)
		self.pos = self.pos + direction * (d * re);
		//println!("new pos: {}", self.pos);
	}
}

pub struct VivaldiRouting {
	nodes: Vec<Node>,
	time: u32,
	rtt: f32
}

//https://pdos.csail.mit.edu/papers/vivaldi:sigcomm/paper.pdf
impl VivaldiRouting {
	pub fn new() -> Self {
		Self {
			nodes: vec![],
			time: 0,
			rtt: 1.5
		}
	}

	// get median distance change
	pub fn get_convergence(&self) -> f32 {
		let mut d = 0.0;
		let mut c = 0.0;
		for node in &self.nodes {
			d += node.pos_old.distance(&node.pos);
			c += 1.0;
		}
		d / c
	}

}

impl RoutingAlgorithm for VivaldiRouting
{
	fn reset(&mut self, len: usize) {
		self.nodes = vec![Node::new(); len];
		self.time = 0;
	}

	fn get_node(&self, id: ID, key: &str, out: &mut std::fmt::Write) -> Result<(), std::fmt::Error> {
		match key {
			"name" => {
				let pos = self.nodes[id as usize].pos;
				write!(out, "{:.1}/{:.1}/{:.1}", pos.x(), pos.y(), pos.z())?;
			},
			_ => {}
		}
		Ok(())
	}

	fn get(&self, key: &str, out: &mut std::fmt::Write) -> Result<(), std::fmt::Error> {
		match key {
			"rtt" => {
				write!(out, "{}", self.rtt)?;
			},
			"name" => {
				write!(out, "Vivaldi")?;
			},
			"description" => {
				write!(out, "Use Vivaldi coordinates to allow routing.")?;
			},
			"convergence" => {
				write!(out, "{}", self.get_convergence())?;
			},
			_ => {}
		}
		Ok(())
	}

	fn set(&mut self, key: &str, value: &str) -> Result<(), std::fmt::Error> {
		match key {
			"rtt" => {
				if let Ok(rtt) = value.parse() {
					self.rtt = rtt;
				} else {
					println!("invalid rtt value");
				}
			},
			_ => {}
		}
		Ok(())
	}

	fn step(&mut self, io: &mut Io) {
		self.time += 1;

		// fade out old entries
		for node in &mut self.nodes {
			node.pos_old = node.pos;
			node.timeout_entries(self.time);
		}

		// simulate broadcast traffic
		for (from, to) in io.link_iter() {
			let pos_old = self.nodes[from as usize].pos_old;
			self.nodes[to as usize].update(from, pos_old, 1.0, self.time, self.rtt);
		}
	}

	fn route(&self, packet: &TestPacket) -> Option<ID> {
		// we pretend to know the destination locator instead of the id
		let dst_pos = &self.nodes[packet.destination as usize].pos;
		self.nodes[packet.receiver as usize].route(packet, dst_pos)
	}
}
<commit_msg>some experiments with the vivaldi algorithm<commit_after>use std::f32;
use std::u32;

use crate::utils::*;
use crate::graph::*;
use crate::sim::{Io, TestPacket, RoutingAlgorithm};
use std::ops::{AddAssign, DivAssign, Index, Add, Mul, Div, Sub, Deref};

#[derive(Clone, Copy, PartialEq)]
struct VVec {
	data: [f32; 8]
}

impl VVec {
	pub fn new() -> Self {
		Self { data: [0.0; 8] }
	}

	pub fn new_nan() -> Self {
		Self { data: [f32::NAN; 8] }
	}

	pub fn vec_sub(&self, v: &VVec) -> VVec {
		let mut ret = VVec::new();
		for i in 0..self.data.len() {
			ret.data[i] = self.data[i] - v.data[i];
		}
		ret
	}

	pub fn vec_add(&self, v: &VVec) -> VVec {
		let mut ret = VVec::new();
		for i in 0..self.data.len() {
			ret.data[i] = self.data[i] + v.data[i];
		}
		ret
	}

	pub fn length(&self) -> f32 {
		let mut ret = 0.0;
		for i in 0..self.data.len() {
			ret += self.data[i] * self.data[i];
		}
		ret.sqrt()
	}

	pub fn unit(&self) -> VVec {
		self.scalar_mul(1.0 / self.length())
	}

	pub fn angle(&self, v: &VVec) -> f32 {
		(self.unit() * v.unit()).acos()
	}

	pub fn vec_mul(&self, v: &VVec) -> f32 {
		let mut ret = 0.0;
		for i in 0..self.data.len() {
			ret += self.data[i] * v.data[i];
		}
		ret
	}

	pub fn scalar_mul(&self, s: f32) -> VVec {
		let mut ret = self.clone();
		for i in 0..ret.data.len() {
			ret.data[i] *= s
		}
		ret
	}

	pub fn scalar_div(&self, s: f32) -> VVec {
		self.scalar_mul(1.0 / s)
	}

	pub fn distance(&self, v: &VVec) -> f32 {
		self.vec_sub(v).length()
	}

	pub fn direction(&self, v: &VVec) -> VVec {
		self.vec_sub(v).unit()
	}

	pub fn is_near_null(&self, eta: f32) -> bool {
		for n in &self.data {
			if (*n >= eta) && (*n <= -eta) {
				return false;
			}
		}
		true
	}

	pub fn is_finite(&self) -> bool {
		for n in &self.data {
			if !n.is_finite() {
				return false;
			}
		}
		true
	}

	pub fn to_finite(&self) -> Self {
		let mut ret = Self::new_nan();
		let mut i = 0;
		for n in &self.data {
			if n.is_finite() {
				ret.data[i] = *n;
				i += 1;
			}
		}
		ret
	}

	pub fn as_slice(&self) -> &[f32; 8] {
		&self.data
	}

	pub fn random_unit() -> VVec {
		VVec::random_in_area(1.0).unit()
	}

	// random around in the box of (0, 0, 0)
	pub fn random_in_area(r: f32) -> VVec {
		let mut ret = VVec::new();
		for i in 0..ret.data.len() {
			ret.data[i] = (2.0 * rand::random::<f32>() - 1.0) * r;
		}
		ret
	}
}

impl Index<usize> for VVec {
    type Output = f32;

    fn index(&self, idx: usize) -> &Self::Output {
        &self.data[idx]
    }
}

impl AddAssign<VVec> for VVec {
	fn add_assign(&mut self, v: VVec) {
		*self = *self + v;
	}
}

impl DivAssign<f32> for VVec {
	fn div_assign(&mut self, s: f32) {
		*self = *self / s;
	}
}

impl Add<VVec> for VVec {
	type Output = VVec;

	fn add(self, v: VVec) -> VVec {
		self.vec_add(&v)
	}
}

impl Sub<VVec> for VVec {
	type Output = VVec;

	fn sub(self, rhs: VVec) -> VVec {
		self.vec_sub(&rhs)
	}
}

impl Mul<VVec> for VVec {
	type Output = f32;

	fn mul(self, rhs: VVec) -> f32 {
		self.vec_mul(&rhs)
	}
}

impl Mul<f32> for VVec {
	type Output = VVec;

	fn mul(self, rhs: f32) -> VVec {
		self.scalar_mul(rhs)
	}
}

impl Div<f32> for VVec {
	type Output = VVec;

	fn div(self, rhs: f32) -> VVec {
		self.scalar_div(rhs)
	}
}

#[derive(Clone)]
struct Neighbor {
	id: ID,
	pos: VVec,
	error: f32,
	last_updated: u32
}

impl PartialEq for Neighbor {
	fn eq(&self, other: &Neighbor) -> bool {
		self.id == other.id
	}
}

#[derive(Clone)]
struct Node {
	pos: VVec,
	error: f32,
	pos_old: VVec,
	neighbors: Vec<Neighbor>,
}

impl Node {
	fn new() -> Self {
		Self {
			pos: VVec::new(),
			error: 0.0,
			pos_old: VVec::new(),
			neighbors: vec![],
		}
	}

	fn reset(&mut self) {
		self.pos = VVec::new();
		self.error = 0.0;
		self.pos_old = VVec::new();
		self.neighbors.clear();
	}

	fn timeout_entries(&mut self, time: u32) {
		vec_filter(&mut self.neighbors, |ref e| (e.last_updated + 5) >= time);
	}

	fn route(&self, packet: &TestPacket, dst_pos: &VVec) -> Option<ID> {
		let mut d_next = f32::INFINITY;
		let mut n_next = None;

		for v in &self.neighbors {
			let d = v.pos.distance(dst_pos);
			if d < d_next {
				d_next = d;
				n_next = Some(v.id);
			}
		}

		n_next
	}

	fn update(&mut self, from_id: ID, from_pos: VVec, from_error: f32, time: u32, rtt: f32) {
		vec_add_entry(&mut self.neighbors,
			&Neighbor {
				id: from_id,
				pos: from_pos,
				error: from_error,
				last_updated: time
			}
		);

		self.vivaldi_update(&from_pos, from_error, rtt);
	}

	fn cut_old_pos(&mut self) {
		let n = std::cmp::min(std::cmp::max(self.neighbors.len(), 1), 8);
		println!("n: {}, neigh: {}", n, self.neighbors.len());
		for i in n..8 {
			self.pos_old.data[i] = 0.0;
		}
		/*
		for i in 0..n {
			if !self.pos_old[i].is_finite() {
				self.pos_old.data[i] = 0.0;
			}
		}
		for i in n..8 {
			self.pos_old.data[i] = f32::NAN;
		}*/
	}

	// Vivaldi algorithm
	fn vivaldi_update(&mut self, pos: &VVec, error: f32, rtt: f32) {
		//let rtt = self.rtt;
		let ce = 0.25;
		let cc = 0.25;

		// w = e_i / (e_i + e_j)
		let w = if (self.error > 0.0) && (error > 0.0) {
			self.error / (self.error + error)
		} else {
			1.0
		};

		// x_i - x_j
		let ab = self.pos - *pos;

		// rtt - |x_i - x_j|
		let re = rtt - ab.length();

		// e_s = ||x_i - x_j| - rtt| / rtt
		let es = re.abs() / rtt;

		// e_i = e_s * c_e * w + e_i * (1 - c_e * w)
		self.error = es * ce * w + self.error * (1.0 - ce * w);

		// ∂ = c_c * w
		let d = cc * w;

		// Choose random direction if both positions are identical
		let direction = if ab.is_near_null(0.01) {
			//println!("random direction");
			VVec::random_unit()
		} else {
			ab
		};

		//println!("old pos: {}, {} {} {}", self.pos, direction, w, re);

		// x_i = x_i + ∂ * (rtt - |x_i - x_j|) * u(x_i - x_j)
		self.pos = self.pos + direction * (d * re);
		//println!("new pos: {}", self.pos);
	}
}

pub struct VivaldiRouting {
	nodes: Vec<Node>,
	time: u32,
	rtt: f32
}

//https://pdos.csail.mit.edu/papers/vivaldi:sigcomm/paper.pdf
impl VivaldiRouting {
	pub fn new() -> Self {
		Self {
			nodes: vec![],
			time: 0,
			rtt: 1.5
		}
	}

	// get median distance change
	pub fn get_convergence(&self) -> f32 {
		let mut d = 0.0;
		let mut c = 0.0;
		for node in &self.nodes {
			d += node.pos_old.distance(&node.pos);
			c += 1.0;
		}
		d / c
	}

}

impl RoutingAlgorithm for VivaldiRouting
{
	fn reset(&mut self, len: usize) {
		self.nodes = vec![Node::new(); len];
		self.time = 0;
	}

	fn get_node(&self, id: ID, key: &str, out: &mut std::fmt::Write) -> Result<(), std::fmt::Error> {
		match key {
			"name" => {
				let pos = self.nodes[id as usize].pos;
				write!(out, "{:.1}/{:.1}/{:.1}", pos[0], pos[1], pos[2])?;
			},
			_ => {}
		}
		Ok(())
	}

	fn get(&self, key: &str, out: &mut std::fmt::Write) -> Result<(), std::fmt::Error> {
		match key {
			"rtt" => {
				write!(out, "{}", self.rtt)?;
			},
			"name" => {
				write!(out, "Vivaldi")?;
			},
			"description" => {
				write!(out, "Use Vivaldi coordinates to allow routing.")?;
			},
			"convergence" => {
				write!(out, "{}", self.get_convergence())?;
			},
			_ => {}
		}
		Ok(())
	}

	fn set(&mut self, key: &str, value: &str) -> Result<(), std::fmt::Error> {
		match key {
			"rtt" => {
				if let Ok(rtt) = value.parse() {
					self.rtt = rtt;
				} else {
					println!("invalid rtt value");
				}
			},
			_ => {}
		}
		Ok(())
	}

	fn step(&mut self, io: &mut Io) {
		self.time += 1;

		// fade out old entries
		for node in &mut self.nodes {
			node.pos_old = node.pos;
			node.timeout_entries(self.time);
			node.cut_old_pos();
		}

		// simulate broadcast traffic
		for (from, to) in io.link_iter() {
			let pos_old = self.nodes[from as usize].pos_old;
			self.nodes[to as usize].update(from, pos_old, 1.0, self.time, self.rtt);
		}
	}

	fn route(&self, packet: &TestPacket) -> Option<ID> {
		// we pretend to know the destination locator instead of the id
		let dst_pos = &self.nodes[packet.destination as usize].pos;
		self.nodes[packet.receiver as usize].route(packet, dst_pos)
	}
}
<|endoftext|>


<commit_before>//! See `CompletionItem` structure.

use std::fmt;

use hir::{Documentation, ModPath, Mutability};
use ide_db::helpers::{
    insert_use::{self, ImportScope, MergeBehavior},
    mod_path_to_ast, SnippetCap,
};
use stdx::assert_never;
use syntax::{algo, TextRange};
use text_edit::TextEdit;

/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
#[derive(Clone)]
pub struct CompletionItem {
    /// Used only internally in tests, to check only specific kind of
    /// completion (postfix, keyword, reference, etc).
    #[allow(unused)]
    pub(crate) completion_kind: CompletionKind,
    /// Label in the completion pop up which identifies completion.
    label: String,
    /// Range of identifier that is being completed.
    ///
    /// It should be used primarily for UI, but we also use this to convert
    /// genetic TextEdit into LSP's completion edit (see conv.rs).
    ///
    /// `source_range` must contain the completion offset. `insert_text` should
    /// start with what `source_range` points to, or VSCode will filter out the
    /// completion silently.
    source_range: TextRange,
    /// What happens when user selects this item.
    ///
    /// Typically, replaces `source_range` with new identifier.
    text_edit: TextEdit,

    insert_text_format: InsertTextFormat,

    /// What item (struct, function, etc) are we completing.
    kind: Option<CompletionItemKind>,

    /// Lookup is used to check if completion item indeed can complete current
    /// ident.
    ///
    /// That is, in `foo.bar$0` lookup of `abracadabra` will be accepted (it
    /// contains `bar` sub sequence), and `quux` will rejected.
    lookup: Option<String>,

    /// Additional info to show in the UI pop up.
    detail: Option<String>,
    documentation: Option<Documentation>,

    /// Whether this item is marked as deprecated
    deprecated: bool,

    /// If completing a function call, ask the editor to show parameter popup
    /// after completion.
    trigger_call_info: bool,

    /// Score is useful to pre select or display in better order completion items
    score: Option<CompletionScore>,

    /// Indicates that a reference or mutable reference to this variable is a
    /// possible match.
    ref_match: Option<(Mutability, CompletionScore)>,

    /// The import data to add to completion's edits.
    import_to_add: Option<ImportEdit>,
}

// We use custom debug for CompletionItem to make snapshot tests more readable.
impl fmt::Debug for CompletionItem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = f.debug_struct("CompletionItem");
        s.field("label", &self.label()).field("source_range", &self.source_range());
        if self.text_edit().len() == 1 {
            let atom = &self.text_edit().iter().next().unwrap();
            s.field("delete", &atom.delete);
            s.field("insert", &atom.insert);
        } else {
            s.field("text_edit", &self.text_edit);
        }
        if let Some(kind) = self.kind().as_ref() {
            s.field("kind", kind);
        }
        if self.lookup() != self.label() {
            s.field("lookup", &self.lookup());
        }
        if let Some(detail) = self.detail() {
            s.field("detail", &detail);
        }
        if let Some(documentation) = self.documentation() {
            s.field("documentation", &documentation);
        }
        if self.deprecated {
            s.field("deprecated", &true);
        }
        if let Some(score) = &self.score {
            s.field("score", score);
        }
        if self.trigger_call_info {
            s.field("trigger_call_info", &true);
        }
        s.finish()
    }
}

#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)]
pub enum CompletionScore {
    /// If only type match
    TypeMatch,
    /// If type and name match
    TypeAndNameMatch,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompletionItemKind {
    Snippet,
    Keyword,
    Module,
    Function,
    BuiltinType,
    Struct,
    Enum,
    EnumVariant,
    Binding,
    Field,
    Static,
    Const,
    Trait,
    TypeAlias,
    Method,
    TypeParam,
    Macro,
    Attribute,
    UnresolvedReference,
}

impl CompletionItemKind {
    #[cfg(test)]
    pub(crate) fn tag(&self) -> &'static str {
        match self {
            CompletionItemKind::Attribute => "at",
            CompletionItemKind::Binding => "bn",
            CompletionItemKind::BuiltinType => "bt",
            CompletionItemKind::Const => "ct",
            CompletionItemKind::Enum => "en",
            CompletionItemKind::EnumVariant => "ev",
            CompletionItemKind::Field => "fd",
            CompletionItemKind::Function => "fn",
            CompletionItemKind::Keyword => "kw",
            CompletionItemKind::Macro => "ma",
            CompletionItemKind::Method => "me",
            CompletionItemKind::Module => "md",
            CompletionItemKind::Snippet => "sn",
            CompletionItemKind::Static => "sc",
            CompletionItemKind::Struct => "st",
            CompletionItemKind::Trait => "tt",
            CompletionItemKind::TypeAlias => "ta",
            CompletionItemKind::TypeParam => "tp",
            CompletionItemKind::UnresolvedReference => "??",
        }
    }
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub(crate) enum CompletionKind {
    /// Parser-based keyword completion.
    Keyword,
    /// Your usual "complete all valid identifiers".
    Reference,
    /// "Secret sauce" completions.
    Magic,
    Snippet,
    Postfix,
    BuiltinType,
    Attribute,
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum InsertTextFormat {
    PlainText,
    Snippet,
}

impl CompletionItem {
    pub(crate) fn new(
        completion_kind: CompletionKind,
        source_range: TextRange,
        label: impl Into<String>,
    ) -> Builder {
        let label = label.into();
        Builder {
            source_range,
            completion_kind,
            label,
            insert_text: None,
            insert_text_format: InsertTextFormat::PlainText,
            detail: None,
            documentation: None,
            lookup: None,
            kind: None,
            text_edit: None,
            deprecated: None,
            trigger_call_info: None,
            score: None,
            ref_match: None,
            import_to_add: None,
        }
    }

    /// What user sees in pop-up in the UI.
    pub fn label(&self) -> &str {
        &self.label
    }
    pub fn source_range(&self) -> TextRange {
        self.source_range
    }

    pub fn insert_text_format(&self) -> InsertTextFormat {
        self.insert_text_format
    }

    pub fn text_edit(&self) -> &TextEdit {
        &self.text_edit
    }

    /// Short one-line additional information, like a type
    pub fn detail(&self) -> Option<&str> {
        self.detail.as_deref()
    }
    /// A doc-comment
    pub fn documentation(&self) -> Option<Documentation> {
        self.documentation.clone()
    }
    /// What string is used for filtering.
    pub fn lookup(&self) -> &str {
        self.lookup.as_deref().unwrap_or(&self.label)
    }

    pub fn kind(&self) -> Option<CompletionItemKind> {
        self.kind
    }

    pub fn deprecated(&self) -> bool {
        self.deprecated
    }

    pub fn score(&self) -> Option<CompletionScore> {
        self.score
    }

    pub fn trigger_call_info(&self) -> bool {
        self.trigger_call_info
    }

    pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> {
        self.ref_match
    }

    pub fn import_to_add(&self) -> Option<&ImportEdit> {
        self.import_to_add.as_ref()
    }
}

/// An extra import to add after the completion is applied.
#[derive(Debug, Clone)]
pub struct ImportEdit {
    pub import_path: ModPath,
    pub import_scope: ImportScope,
}

impl ImportEdit {
    /// Attempts to insert the import to the given scope, producing a text edit.
    /// May return no edit in edge cases, such as scope already containing the import.
    pub fn to_text_edit(&self, merge_behavior: Option<MergeBehavior>) -> Option<TextEdit> {
        let _p = profile::span("ImportEdit::to_text_edit");

        let rewriter = insert_use::insert_use(
            &self.import_scope,
            mod_path_to_ast(&self.import_path),
            merge_behavior,
        );
        let old_ast = rewriter.rewrite_root()?;
        let mut import_insert = TextEdit::builder();
        algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert);

        Some(import_insert.finish())
    }
}

/// A helper to make `CompletionItem`s.
#[must_use]
#[derive(Clone)]
pub(crate) struct Builder {
    source_range: TextRange,
    completion_kind: CompletionKind,
    import_to_add: Option<ImportEdit>,
    label: String,
    insert_text: Option<String>,
    insert_text_format: InsertTextFormat,
    detail: Option<String>,
    documentation: Option<Documentation>,
    lookup: Option<String>,
    kind: Option<CompletionItemKind>,
    text_edit: Option<TextEdit>,
    deprecated: Option<bool>,
    trigger_call_info: Option<bool>,
    score: Option<CompletionScore>,
    ref_match: Option<(Mutability, CompletionScore)>,
}

impl Builder {
    pub(crate) fn build(self) -> CompletionItem {
        let _p = profile::span("item::Builder::build");

        let mut label = self.label;
        let mut lookup = self.lookup;
        let mut insert_text = self.insert_text;

        if let Some(import_to_add) = self.import_to_add.as_ref() {
            let mut import_path_without_last_segment = import_to_add.import_path.to_owned();
            let _ = import_path_without_last_segment.segments.pop();

            if !import_path_without_last_segment.segments.is_empty() {
                if lookup.is_none() {
                    lookup = Some(label.clone());
                }
                if insert_text.is_none() {
                    insert_text = Some(label.clone());
                }
                label = format!("{}::{}", import_path_without_last_segment, label);
            }
        }

        let text_edit = match self.text_edit {
            Some(it) => it,
            None => {
                TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone()))
            }
        };

        CompletionItem {
            source_range: self.source_range,
            label,
            insert_text_format: self.insert_text_format,
            text_edit,
            detail: self.detail,
            documentation: self.documentation,
            lookup,
            kind: self.kind,
            completion_kind: self.completion_kind,
            deprecated: self.deprecated.unwrap_or(false),
            trigger_call_info: self.trigger_call_info.unwrap_or(false),
            score: self.score,
            ref_match: self.ref_match,
            import_to_add: self.import_to_add,
        }
    }
    pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
        self.lookup = Some(lookup.into());
        self
    }
    pub(crate) fn label(mut self, label: impl Into<String>) -> Builder {
        self.label = label.into();
        self
    }
    pub(crate) fn insert_text(mut self, insert_text: impl Into<String>) -> Builder {
        self.insert_text = Some(insert_text.into());
        self
    }
    pub(crate) fn insert_snippet(
        mut self,
        _cap: SnippetCap,
        snippet: impl Into<String>,
    ) -> Builder {
        self.insert_text_format = InsertTextFormat::Snippet;
        self.insert_text(snippet)
    }
    pub(crate) fn kind(mut self, kind: CompletionItemKind) -> Builder {
        self.kind = Some(kind);
        self
    }
    pub(crate) fn text_edit(mut self, edit: TextEdit) -> Builder {
        self.text_edit = Some(edit);
        self
    }
    pub(crate) fn snippet_edit(mut self, _cap: SnippetCap, edit: TextEdit) -> Builder {
        self.insert_text_format = InsertTextFormat::Snippet;
        self.text_edit(edit)
    }
    #[allow(unused)]
    pub(crate) fn detail(self, detail: impl Into<String>) -> Builder {
        self.set_detail(Some(detail))
    }
    pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
        self.detail = detail.map(Into::into);
        if let Some(detail) = &self.detail {
            assert_never!(detail.contains('\n'), "multiline detail: {}", detail);
        }
        self
    }
    #[allow(unused)]
    pub(crate) fn documentation(self, docs: Documentation) -> Builder {
        self.set_documentation(Some(docs))
    }
    pub(crate) fn set_documentation(mut self, docs: Option<Documentation>) -> Builder {
        self.documentation = docs.map(Into::into);
        self
    }
    pub(crate) fn set_deprecated(mut self, deprecated: bool) -> Builder {
        self.deprecated = Some(deprecated);
        self
    }
    pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder {
        self.score = Some(score);
        self
    }
    pub(crate) fn trigger_call_info(mut self) -> Builder {
        self.trigger_call_info = Some(true);
        self
    }
    pub(crate) fn add_import(mut self, import_to_add: Option<ImportEdit>) -> Builder {
        self.import_to_add = import_to_add;
        self
    }
    pub(crate) fn set_ref_match(
        mut self,
        ref_match: Option<(Mutability, CompletionScore)>,
    ) -> Builder {
        self.ref_match = ref_match;
        self
    }
}

impl<'a> Into<CompletionItem> for Builder {
    fn into(self) -> CompletionItem {
        self.build()
    }
}
<commit_msg>Use assert_never properly<commit_after>//! See `CompletionItem` structure.

use std::fmt;

use hir::{Documentation, ModPath, Mutability};
use ide_db::helpers::{
    insert_use::{self, ImportScope, MergeBehavior},
    mod_path_to_ast, SnippetCap,
};
use stdx::assert_never;
use syntax::{algo, TextRange};
use text_edit::TextEdit;

/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
#[derive(Clone)]
pub struct CompletionItem {
    /// Used only internally in tests, to check only specific kind of
    /// completion (postfix, keyword, reference, etc).
    #[allow(unused)]
    pub(crate) completion_kind: CompletionKind,
    /// Label in the completion pop up which identifies completion.
    label: String,
    /// Range of identifier that is being completed.
    ///
    /// It should be used primarily for UI, but we also use this to convert
    /// genetic TextEdit into LSP's completion edit (see conv.rs).
    ///
    /// `source_range` must contain the completion offset. `insert_text` should
    /// start with what `source_range` points to, or VSCode will filter out the
    /// completion silently.
    source_range: TextRange,
    /// What happens when user selects this item.
    ///
    /// Typically, replaces `source_range` with new identifier.
    text_edit: TextEdit,

    insert_text_format: InsertTextFormat,

    /// What item (struct, function, etc) are we completing.
    kind: Option<CompletionItemKind>,

    /// Lookup is used to check if completion item indeed can complete current
    /// ident.
    ///
    /// That is, in `foo.bar$0` lookup of `abracadabra` will be accepted (it
    /// contains `bar` sub sequence), and `quux` will rejected.
    lookup: Option<String>,

    /// Additional info to show in the UI pop up.
    detail: Option<String>,
    documentation: Option<Documentation>,

    /// Whether this item is marked as deprecated
    deprecated: bool,

    /// If completing a function call, ask the editor to show parameter popup
    /// after completion.
    trigger_call_info: bool,

    /// Score is useful to pre select or display in better order completion items
    score: Option<CompletionScore>,

    /// Indicates that a reference or mutable reference to this variable is a
    /// possible match.
    ref_match: Option<(Mutability, CompletionScore)>,

    /// The import data to add to completion's edits.
    import_to_add: Option<ImportEdit>,
}

// We use custom debug for CompletionItem to make snapshot tests more readable.
impl fmt::Debug for CompletionItem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = f.debug_struct("CompletionItem");
        s.field("label", &self.label()).field("source_range", &self.source_range());
        if self.text_edit().len() == 1 {
            let atom = &self.text_edit().iter().next().unwrap();
            s.field("delete", &atom.delete);
            s.field("insert", &atom.insert);
        } else {
            s.field("text_edit", &self.text_edit);
        }
        if let Some(kind) = self.kind().as_ref() {
            s.field("kind", kind);
        }
        if self.lookup() != self.label() {
            s.field("lookup", &self.lookup());
        }
        if let Some(detail) = self.detail() {
            s.field("detail", &detail);
        }
        if let Some(documentation) = self.documentation() {
            s.field("documentation", &documentation);
        }
        if self.deprecated {
            s.field("deprecated", &true);
        }
        if let Some(score) = &self.score {
            s.field("score", score);
        }
        if self.trigger_call_info {
            s.field("trigger_call_info", &true);
        }
        s.finish()
    }
}

#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)]
pub enum CompletionScore {
    /// If only type match
    TypeMatch,
    /// If type and name match
    TypeAndNameMatch,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompletionItemKind {
    Snippet,
    Keyword,
    Module,
    Function,
    BuiltinType,
    Struct,
    Enum,
    EnumVariant,
    Binding,
    Field,
    Static,
    Const,
    Trait,
    TypeAlias,
    Method,
    TypeParam,
    Macro,
    Attribute,
    UnresolvedReference,
}

impl CompletionItemKind {
    #[cfg(test)]
    pub(crate) fn tag(&self) -> &'static str {
        match self {
            CompletionItemKind::Attribute => "at",
            CompletionItemKind::Binding => "bn",
            CompletionItemKind::BuiltinType => "bt",
            CompletionItemKind::Const => "ct",
            CompletionItemKind::Enum => "en",
            CompletionItemKind::EnumVariant => "ev",
            CompletionItemKind::Field => "fd",
            CompletionItemKind::Function => "fn",
            CompletionItemKind::Keyword => "kw",
            CompletionItemKind::Macro => "ma",
            CompletionItemKind::Method => "me",
            CompletionItemKind::Module => "md",
            CompletionItemKind::Snippet => "sn",
            CompletionItemKind::Static => "sc",
            CompletionItemKind::Struct => "st",
            CompletionItemKind::Trait => "tt",
            CompletionItemKind::TypeAlias => "ta",
            CompletionItemKind::TypeParam => "tp",
            CompletionItemKind::UnresolvedReference => "??",
        }
    }
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub(crate) enum CompletionKind {
    /// Parser-based keyword completion.
    Keyword,
    /// Your usual "complete all valid identifiers".
    Reference,
    /// "Secret sauce" completions.
    Magic,
    Snippet,
    Postfix,
    BuiltinType,
    Attribute,
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum InsertTextFormat {
    PlainText,
    Snippet,
}

impl CompletionItem {
    pub(crate) fn new(
        completion_kind: CompletionKind,
        source_range: TextRange,
        label: impl Into<String>,
    ) -> Builder {
        let label = label.into();
        Builder {
            source_range,
            completion_kind,
            label,
            insert_text: None,
            insert_text_format: InsertTextFormat::PlainText,
            detail: None,
            documentation: None,
            lookup: None,
            kind: None,
            text_edit: None,
            deprecated: None,
            trigger_call_info: None,
            score: None,
            ref_match: None,
            import_to_add: None,
        }
    }

    /// What user sees in pop-up in the UI.
    pub fn label(&self) -> &str {
        &self.label
    }
    pub fn source_range(&self) -> TextRange {
        self.source_range
    }

    pub fn insert_text_format(&self) -> InsertTextFormat {
        self.insert_text_format
    }

    pub fn text_edit(&self) -> &TextEdit {
        &self.text_edit
    }

    /// Short one-line additional information, like a type
    pub fn detail(&self) -> Option<&str> {
        self.detail.as_deref()
    }
    /// A doc-comment
    pub fn documentation(&self) -> Option<Documentation> {
        self.documentation.clone()
    }
    /// What string is used for filtering.
    pub fn lookup(&self) -> &str {
        self.lookup.as_deref().unwrap_or(&self.label)
    }

    pub fn kind(&self) -> Option<CompletionItemKind> {
        self.kind
    }

    pub fn deprecated(&self) -> bool {
        self.deprecated
    }

    pub fn score(&self) -> Option<CompletionScore> {
        self.score
    }

    pub fn trigger_call_info(&self) -> bool {
        self.trigger_call_info
    }

    pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> {
        self.ref_match
    }

    pub fn import_to_add(&self) -> Option<&ImportEdit> {
        self.import_to_add.as_ref()
    }
}

/// An extra import to add after the completion is applied.
#[derive(Debug, Clone)]
pub struct ImportEdit {
    pub import_path: ModPath,
    pub import_scope: ImportScope,
}

impl ImportEdit {
    /// Attempts to insert the import to the given scope, producing a text edit.
    /// May return no edit in edge cases, such as scope already containing the import.
    pub fn to_text_edit(&self, merge_behavior: Option<MergeBehavior>) -> Option<TextEdit> {
        let _p = profile::span("ImportEdit::to_text_edit");

        let rewriter = insert_use::insert_use(
            &self.import_scope,
            mod_path_to_ast(&self.import_path),
            merge_behavior,
        );
        let old_ast = rewriter.rewrite_root()?;
        let mut import_insert = TextEdit::builder();
        algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert);

        Some(import_insert.finish())
    }
}

/// A helper to make `CompletionItem`s.
#[must_use]
#[derive(Clone)]
pub(crate) struct Builder {
    source_range: TextRange,
    completion_kind: CompletionKind,
    import_to_add: Option<ImportEdit>,
    label: String,
    insert_text: Option<String>,
    insert_text_format: InsertTextFormat,
    detail: Option<String>,
    documentation: Option<Documentation>,
    lookup: Option<String>,
    kind: Option<CompletionItemKind>,
    text_edit: Option<TextEdit>,
    deprecated: Option<bool>,
    trigger_call_info: Option<bool>,
    score: Option<CompletionScore>,
    ref_match: Option<(Mutability, CompletionScore)>,
}

impl Builder {
    pub(crate) fn build(self) -> CompletionItem {
        let _p = profile::span("item::Builder::build");

        let mut label = self.label;
        let mut lookup = self.lookup;
        let mut insert_text = self.insert_text;

        if let Some(import_to_add) = self.import_to_add.as_ref() {
            let mut import_path_without_last_segment = import_to_add.import_path.to_owned();
            let _ = import_path_without_last_segment.segments.pop();

            if !import_path_without_last_segment.segments.is_empty() {
                if lookup.is_none() {
                    lookup = Some(label.clone());
                }
                if insert_text.is_none() {
                    insert_text = Some(label.clone());
                }
                label = format!("{}::{}", import_path_without_last_segment, label);
            }
        }

        let text_edit = match self.text_edit {
            Some(it) => it,
            None => {
                TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone()))
            }
        };

        CompletionItem {
            source_range: self.source_range,
            label,
            insert_text_format: self.insert_text_format,
            text_edit,
            detail: self.detail,
            documentation: self.documentation,
            lookup,
            kind: self.kind,
            completion_kind: self.completion_kind,
            deprecated: self.deprecated.unwrap_or(false),
            trigger_call_info: self.trigger_call_info.unwrap_or(false),
            score: self.score,
            ref_match: self.ref_match,
            import_to_add: self.import_to_add,
        }
    }
    pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
        self.lookup = Some(lookup.into());
        self
    }
    pub(crate) fn label(mut self, label: impl Into<String>) -> Builder {
        self.label = label.into();
        self
    }
    pub(crate) fn insert_text(mut self, insert_text: impl Into<String>) -> Builder {
        self.insert_text = Some(insert_text.into());
        self
    }
    pub(crate) fn insert_snippet(
        mut self,
        _cap: SnippetCap,
        snippet: impl Into<String>,
    ) -> Builder {
        self.insert_text_format = InsertTextFormat::Snippet;
        self.insert_text(snippet)
    }
    pub(crate) fn kind(mut self, kind: CompletionItemKind) -> Builder {
        self.kind = Some(kind);
        self
    }
    pub(crate) fn text_edit(mut self, edit: TextEdit) -> Builder {
        self.text_edit = Some(edit);
        self
    }
    pub(crate) fn snippet_edit(mut self, _cap: SnippetCap, edit: TextEdit) -> Builder {
        self.insert_text_format = InsertTextFormat::Snippet;
        self.text_edit(edit)
    }
    #[allow(unused)]
    pub(crate) fn detail(self, detail: impl Into<String>) -> Builder {
        self.set_detail(Some(detail))
    }
    pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
        self.detail = detail.map(Into::into);
        if let Some(detail) = &self.detail {
            if assert_never!(detail.contains('\n'), "multiline detail: {}", detail) {
                self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string());
            }
        }
        self
    }
    #[allow(unused)]
    pub(crate) fn documentation(self, docs: Documentation) -> Builder {
        self.set_documentation(Some(docs))
    }
    pub(crate) fn set_documentation(mut self, docs: Option<Documentation>) -> Builder {
        self.documentation = docs.map(Into::into);
        self
    }
    pub(crate) fn set_deprecated(mut self, deprecated: bool) -> Builder {
        self.deprecated = Some(deprecated);
        self
    }
    pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder {
        self.score = Some(score);
        self
    }
    pub(crate) fn trigger_call_info(mut self) -> Builder {
        self.trigger_call_info = Some(true);
        self
    }
    pub(crate) fn add_import(mut self, import_to_add: Option<ImportEdit>) -> Builder {
        self.import_to_add = import_to_add;
        self
    }
    pub(crate) fn set_ref_match(
        mut self,
        ref_match: Option<(Mutability, CompletionScore)>,
    ) -> Builder {
        self.ref_match = ref_match;
        self
    }
}

impl<'a> Into<CompletionItem> for Builder {
    fn into(self) -> CompletionItem {
        self.build()
    }
}
<|endoftext|>


<commit_before>//! Re-export diagnostics such that clients of `hir` don't have to depend on
//! low-level crates.
//!
//! This probably isn't the best way to do this -- ideally, diagnistics should
//! be expressed in terms of hir types themselves.
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_def::path::ModPath;
use hir_expand::{name::Name, HirFileId, InFile};
use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};

use crate::{MacroKind, Type};

macro_rules! diagnostics {
    ($($diag:ident,)*) => {
        pub enum AnyDiagnostic {$(
            $diag(Box<$diag>),
        )*}

        $(
            impl From<$diag> for AnyDiagnostic {
                fn from(d: $diag) -> AnyDiagnostic {
                    AnyDiagnostic::$diag(Box::new(d))
                }
            }
        )*
    };
}

diagnostics![
    BreakOutsideOfLoop,
    InactiveCode,
    IncorrectCase,
    InvalidDeriveTarget,
    MacroError,
    MalformedDerive,
    MismatchedArgCount,
    MissingFields,
    MissingMatchArms,
    MissingUnsafe,
    NoSuchField,
    ReplaceFilterMapNextWithFindMap,
    TypeMismatch,
    UnimplementedBuiltinMacro,
    UnresolvedExternCrate,
    UnresolvedImport,
    UnresolvedMacroCall,
    UnresolvedModule,
    UnresolvedProcMacro,
];

#[derive(Debug)]
pub struct UnresolvedModule {
    pub decl: InFile<AstPtr<ast::Module>>,
    pub candidates: Box<[String]>,
}

#[derive(Debug)]
pub struct UnresolvedExternCrate {
    pub decl: InFile<AstPtr<ast::ExternCrate>>,
}

#[derive(Debug)]
pub struct UnresolvedImport {
    pub decl: InFile<AstPtr<ast::UseTree>>,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct UnresolvedMacroCall {
    pub macro_call: InFile<SyntaxNodePtr>,
    pub precise_location: Option<TextRange>,
    pub path: ModPath,
    pub is_bang: bool,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct InactiveCode {
    pub node: InFile<SyntaxNodePtr>,
    pub cfg: CfgExpr,
    pub opts: CfgOptions,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct UnresolvedProcMacro {
    pub node: InFile<SyntaxNodePtr>,
    /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange`
    /// to use instead.
    pub precise_location: Option<TextRange>,
    pub macro_name: Option<String>,
    pub kind: MacroKind,
    /// The crate id of the proc-macro this macro belongs to, or `None` if the proc-macro can't be found.
    pub krate: CrateId,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MacroError {
    pub node: InFile<SyntaxNodePtr>,
    pub precise_location: Option<TextRange>,
    pub message: String,
}

#[derive(Debug)]
pub struct UnimplementedBuiltinMacro {
    pub node: InFile<SyntaxNodePtr>,
}

#[derive(Debug)]
pub struct InvalidDeriveTarget {
    pub node: InFile<SyntaxNodePtr>,
}

#[derive(Debug)]
pub struct MalformedDerive {
    pub node: InFile<SyntaxNodePtr>,
}

#[derive(Debug)]
pub struct NoSuchField {
    pub field: InFile<AstPtr<ast::RecordExprField>>,
}

#[derive(Debug)]
pub struct BreakOutsideOfLoop {
    pub expr: InFile<AstPtr<ast::Expr>>,
}

#[derive(Debug)]
pub struct MissingUnsafe {
    pub expr: InFile<AstPtr<ast::Expr>>,
}

#[derive(Debug)]
pub struct MissingFields {
    pub file: HirFileId,
    pub field_list_parent: Either<AstPtr<ast::RecordExpr>, AstPtr<ast::RecordPat>>,
    pub field_list_parent_path: Option<AstPtr<ast::Path>>,
    pub missed_fields: Vec<Name>,
}

#[derive(Debug)]
pub struct ReplaceFilterMapNextWithFindMap {
    pub file: HirFileId,
    /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
    pub next_expr: AstPtr<ast::Expr>,
}

#[derive(Debug)]
pub struct MismatchedArgCount {
    pub call_expr: InFile<AstPtr<ast::Expr>>,
    pub expected: usize,
    pub found: usize,
}

#[derive(Debug)]
pub struct MissingMatchArms {
    pub file: HirFileId,
    pub match_expr: AstPtr<ast::Expr>,
    pub uncovered_patterns: String,
}

#[derive(Debug)]
pub struct TypeMismatch {
    // FIXME: add mismatches in patterns as well
    pub expr: InFile<AstPtr<ast::Expr>>,
    pub expected: Type,
    pub actual: Type,
}

pub use hir_ty::diagnostics::IncorrectCase;
<commit_msg>add debug impl for AnyDiagnostic<commit_after>//! Re-export diagnostics such that clients of `hir` don't have to depend on
//! low-level crates.
//!
//! This probably isn't the best way to do this -- ideally, diagnistics should
//! be expressed in terms of hir types themselves.
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_def::path::ModPath;
use hir_expand::{name::Name, HirFileId, InFile};
use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};

use crate::{MacroKind, Type};

macro_rules! diagnostics {
    ($($diag:ident,)*) => {
        #[derive(Debug)]
        pub enum AnyDiagnostic {$(
            $diag(Box<$diag>),
        )*}

        $(
            impl From<$diag> for AnyDiagnostic {
                fn from(d: $diag) -> AnyDiagnostic {
                    AnyDiagnostic::$diag(Box::new(d))
                }
            }
        )*
    };
}

diagnostics![
    BreakOutsideOfLoop,
    InactiveCode,
    IncorrectCase,
    InvalidDeriveTarget,
    MacroError,
    MalformedDerive,
    MismatchedArgCount,
    MissingFields,
    MissingMatchArms,
    MissingUnsafe,
    NoSuchField,
    ReplaceFilterMapNextWithFindMap,
    TypeMismatch,
    UnimplementedBuiltinMacro,
    UnresolvedExternCrate,
    UnresolvedImport,
    UnresolvedMacroCall,
    UnresolvedModule,
    UnresolvedProcMacro,
];

#[derive(Debug)]
pub struct UnresolvedModule {
    pub decl: InFile<AstPtr<ast::Module>>,
    pub candidates: Box<[String]>,
}

#[derive(Debug)]
pub struct UnresolvedExternCrate {
    pub decl: InFile<AstPtr<ast::ExternCrate>>,
}

#[derive(Debug)]
pub struct UnresolvedImport {
    pub decl: InFile<AstPtr<ast::UseTree>>,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct UnresolvedMacroCall {
    pub macro_call: InFile<SyntaxNodePtr>,
    pub precise_location: Option<TextRange>,
    pub path: ModPath,
    pub is_bang: bool,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct InactiveCode {
    pub node: InFile<SyntaxNodePtr>,
    pub cfg: CfgExpr,
    pub opts: CfgOptions,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct UnresolvedProcMacro {
    pub node: InFile<SyntaxNodePtr>,
    /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange`
    /// to use instead.
    pub precise_location: Option<TextRange>,
    pub macro_name: Option<String>,
    pub kind: MacroKind,
    /// The crate id of the proc-macro this macro belongs to, or `None` if the proc-macro can't be found.
    pub krate: CrateId,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MacroError {
    pub node: InFile<SyntaxNodePtr>,
    pub precise_location: Option<TextRange>,
    pub message: String,
}

#[derive(Debug)]
pub struct UnimplementedBuiltinMacro {
    pub node: InFile<SyntaxNodePtr>,
}

#[derive(Debug)]
pub struct InvalidDeriveTarget {
    pub node: InFile<SyntaxNodePtr>,
}

#[derive(Debug)]
pub struct MalformedDerive {
    pub node: InFile<SyntaxNodePtr>,
}

#[derive(Debug)]
pub struct NoSuchField {
    pub field: InFile<AstPtr<ast::RecordExprField>>,
}

#[derive(Debug)]
pub struct BreakOutsideOfLoop {
    pub expr: InFile<AstPtr<ast::Expr>>,
}

#[derive(Debug)]
pub struct MissingUnsafe {
    pub expr: InFile<AstPtr<ast::Expr>>,
}

#[derive(Debug)]
pub struct MissingFields {
    pub file: HirFileId,
    pub field_list_parent: Either<AstPtr<ast::RecordExpr>, AstPtr<ast::RecordPat>>,
    pub field_list_parent_path: Option<AstPtr<ast::Path>>,
    pub missed_fields: Vec<Name>,
}

#[derive(Debug)]
pub struct ReplaceFilterMapNextWithFindMap {
    pub file: HirFileId,
    /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
    pub next_expr: AstPtr<ast::Expr>,
}

#[derive(Debug)]
pub struct MismatchedArgCount {
    pub call_expr: InFile<AstPtr<ast::Expr>>,
    pub expected: usize,
    pub found: usize,
}

#[derive(Debug)]
pub struct MissingMatchArms {
    pub file: HirFileId,
    pub match_expr: AstPtr<ast::Expr>,
    pub uncovered_patterns: String,
}

#[derive(Debug)]
pub struct TypeMismatch {
    // FIXME: add mismatches in patterns as well
    pub expr: InFile<AstPtr<ast::Expr>>,
    pub expected: Type,
    pub actual: Type,
}

pub use hir_ty::diagnostics::IncorrectCase;
<|endoftext|>


<commit_before>use crate::Point;

/// Describes a new visual rectangle.
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Rectangle {
    /// Position of the rectangle.
    position: Point,

    /// Width of the rectangle.
    width: f64,

    /// Height of the rectangle.
    height: f64,
}

impl Rectangle {
    /// Create a new rectangle with the given parameters.
    pub fn new(position: impl Into<Point>, width: f64, height: f64) -> Self {
        Rectangle {
            position: position.into(),
            width,
            height,
        }
    }

    /// Gets x.
    pub fn x(&self) -> f64 {
        self.position.x()
    }

    /// Sets x.
    pub fn set_x(&mut self, x: f64) {
        self.position.set_x(x);
    }

    /// Gets y.
    pub fn y(&self) -> f64 {
        self.position.y()
    }

    /// Sets y.
    pub fn set_y(&mut self, y: f64) {
        self.position.set_y(y);
    }

    /// Gets position as `Point`.
    pub fn position(&self) -> Point {
        self.position
    }

    /// Sets position.
    pub fn set_position(&mut self, position: impl Into<Point>) {
        self.position = position.into();
    }

    /// Gets the width.
    pub fn width(&self) -> f64 {
        self.width
    }

    /// Sets the width.
    pub fn set_width(&mut self, width: f64) {
        self.width = width;
    }

    /// Gets the height.
    pub fn height(&self) -> f64 {
        self.height
    }

    /// Sets the height.
    pub fn set_height(&mut self, height: f64) {
        self.height = height;
    }

    /// Gets the size with width and height.
    pub fn size(&self) -> (f64, f64) {
        (self.width, self.height)
    }

    /// Sets the size with width and height.
    pub fn set_size(&mut self, width: f64, height: f64) {
        self.width = width;
        self.height = height;
    }

    /// Checks if this rect contains the given `point`.
    pub fn contains(&self, point: impl Into<Point>) -> bool {
        let point: Point = point.into();
        point.x() >= self.x()
            && point.x() <= self.x() + self.width()
            && point.y() >= self.y()
            && point.y() <= self.y() + self.height()
    }

    /// Checks if this rect contains the given `rect`.
    pub fn contains_rect(&self, rect: &Rectangle) -> bool {
        let p1 = rect.position();
        let p2 = (p1.x() + rect.width(), p1.y() + rect.height());
        self.contains(p1) && self.contains(p2)
    }

    /// Checks if this rect intersects with the given `rect`.
    pub fn intersects(&self, rect: &Rectangle) -> bool {
        !(rect.x() >= (self.x() + self.width())
            || self.x() >= (rect.x() + rect.width())
            || rect.y() >= (self.y() + self.height())
            || self.y() >= (rect.y() + rect.height()))
    }
}

// --- Conversions ---

impl From<(i32, i32, i32, i32)> for Rectangle {
    fn from(t: (i32, i32, i32, i32)) -> Self {
        Rectangle::new((t.0 as f64, t.1 as f64), t.2 as f64, t.3 as f64)
    }
}

impl From<(f64, f64, f64, f64)> for Rectangle {
    fn from(t: (f64, f64, f64, f64)) -> Self {
        Rectangle::new((t.0, t.1), t.2, t.3)
    }
}

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

    #[test]
    fn test_new() {
        let rect = Rectangle::new((5.0, 10.0), 20.0, 30.0);

        assert_eq!(rect.x(), 5.0);
        assert_eq!(rect.y(), 10.0);
        assert_eq!(rect.width(), 20.0);
        assert_eq!(rect.height(), 30.0);
    }

    #[test]
    fn test_contains() {
        let rect = Rectangle::new((5.0, 10.0), 20.0, 30.0);

        let p = Point::new(5.0, 10.0);
        assert!(rect.contains(p), "{:?}", p);

        let p = Point::new(25.0, 40.0);
        assert!(rect.contains(p), "{:?}", p);

        let p = Point::new(15.0, 15.0);
        assert!(rect.contains(p), "{:?}", p);

        let p = Point::new(30.0, 15.0);
        assert!(!rect.contains(p), "{:?}", p);
    }
}
<commit_msg>Added more test cases and comments for `test_contains`<commit_after>use crate::Point;

/// Describes a new visual rectangle.
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Rectangle {
    /// Position of the rectangle.
    position: Point,

    /// Width of the rectangle.
    width: f64,

    /// Height of the rectangle.
    height: f64,
}

impl Rectangle {
    /// Create a new rectangle with the given parameters.
    pub fn new(position: impl Into<Point>, width: f64, height: f64) -> Self {
        Rectangle {
            position: position.into(),
            width,
            height,
        }
    }

    /// Gets x.
    pub fn x(&self) -> f64 {
        self.position.x()
    }

    /// Sets x.
    pub fn set_x(&mut self, x: f64) {
        self.position.set_x(x);
    }

    /// Gets y.
    pub fn y(&self) -> f64 {
        self.position.y()
    }

    /// Sets y.
    pub fn set_y(&mut self, y: f64) {
        self.position.set_y(y);
    }

    /// Gets position as `Point`.
    pub fn position(&self) -> Point {
        self.position
    }

    /// Sets position.
    pub fn set_position(&mut self, position: impl Into<Point>) {
        self.position = position.into();
    }

    /// Gets the width.
    pub fn width(&self) -> f64 {
        self.width
    }

    /// Sets the width.
    pub fn set_width(&mut self, width: f64) {
        self.width = width;
    }

    /// Gets the height.
    pub fn height(&self) -> f64 {
        self.height
    }

    /// Sets the height.
    pub fn set_height(&mut self, height: f64) {
        self.height = height;
    }

    /// Gets the size with width and height.
    pub fn size(&self) -> (f64, f64) {
        (self.width, self.height)
    }

    /// Sets the size with width and height.
    pub fn set_size(&mut self, width: f64, height: f64) {
        self.width = width;
        self.height = height;
    }

    /// Checks if this rect contains the given `point`.
    pub fn contains(&self, point: impl Into<Point>) -> bool {
        let point: Point = point.into();
        point.x() >= self.x()
            && point.x() <= self.x() + self.width()
            && point.y() >= self.y()
            && point.y() <= self.y() + self.height()
    }

    /// Checks if this rect contains the given `rect`.
    pub fn contains_rect(&self, rect: &Rectangle) -> bool {
        let p1 = rect.position();
        let p2 = (p1.x() + rect.width(), p1.y() + rect.height());
        self.contains(p1) && self.contains(p2)
    }

    /// Checks if this rect intersects with the given `rect`.
    pub fn intersects(&self, rect: &Rectangle) -> bool {
        !(rect.x() >= (self.x() + self.width())
            || self.x() >= (rect.x() + rect.width())
            || rect.y() >= (self.y() + self.height())
            || self.y() >= (rect.y() + rect.height()))
    }
}

// --- Conversions ---

impl From<(i32, i32, i32, i32)> for Rectangle {
    fn from(t: (i32, i32, i32, i32)) -> Self {
        Rectangle::new((t.0 as f64, t.1 as f64), t.2 as f64, t.3 as f64)
    }
}

impl From<(f64, f64, f64, f64)> for Rectangle {
    fn from(t: (f64, f64, f64, f64)) -> Self {
        Rectangle::new((t.0, t.1), t.2, t.3)
    }
}

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

    #[test]
    fn test_new() {
        let rect = Rectangle::new((5.0, 10.0), 20.0, 30.0);

        assert_eq!(rect.x(), 5.0);
        assert_eq!(rect.y(), 10.0);
        assert_eq!(rect.width(), 20.0);
        assert_eq!(rect.height(), 30.0);
    }

    #[test]
    fn test_contains() {
        let rect = Rectangle::new((5.0, 10.0), 20.0, 30.0);

        // Contains point in its origin
        let p = Point::new(5.0, 10.0);
        assert!(rect.contains(p), "{:?}", p);

        // Contains point in its lower right corner
        let p = Point::new(25.0, 40.0);
        assert!(rect.contains(p), "{:?}", p);

        // Contains normal point
        let p = Point::new(15.0, 15.0);
        assert!(rect.contains(p), "{:?}", p);

        // Doesn't contain point with x out of rect
        let p = Point::new(30.0, 15.0);
        assert!(!rect.contains(p), "{:?}", p);

        // Doesn't contain point with y out of rect
        let p = Point::new(15.0, 50.0);
        assert!(!rect.contains(p), "{:?}", p);

        // Doesn't contain point with both x and y out of rect
        let p = Point::new(30.0, 40.0);
        assert!(!rect.contains(p), "{:?}", p);
    }
}
<|endoftext|>