<commit_before>//! A Rust interface for the functionality of the Objective-C runtime.
//!
//! For more information on foreign functions, see Apple's documentation:
//! https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html

use std::c_str::CString;
use std::c_vec::CVec;
use std::kinds::marker::NoCopy;
use std::str::raw::c_str_to_static_slice;
use libc::{c_char, c_int, c_uint, c_void, ptrdiff_t, size_t};
use libc;

use {encode, Encode};

/// A type that represents a method selector.
#[repr(C)]
pub struct Sel {
	ptr: *const c_void,
}

/// A type that represents an instance variable.
pub struct Ivar {
	nocopy: NoCopy,
}

/// A type that represents a method in a class definition.
pub struct Method {
	nocopy: NoCopy,
}

/// A type that represents an Objective-C class.
pub struct Class {
	nocopy: NoCopy,
}

/// A type that represents an instance of a class.
pub struct Object {
	nocopy: NoCopy,
}

/// A pointer to the start of a method implementation.
pub type Imp = extern fn(*mut Object, Sel, ...) -> *mut Object;

#[allow(improper_ctypes)]
#[link(name = "Foundation", kind = "framework")]
extern {
	pub fn sel_registerName(name: *const c_char) -> Sel;
	pub fn sel_getName(sel: Sel) -> *const c_char;

	pub fn class_getName(cls: *const Class) -> *const c_char;
	pub fn class_getInstanceSize(cls: *const Class) -> size_t;
	pub fn class_getInstanceMethod(cls: *const Class, sel: Sel) -> *const Method;
	pub fn class_getInstanceVariable(cls: *const Class, name: *const c_char) -> *const Ivar;
	pub fn class_copyMethodList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Method;
	pub fn class_copyIvarList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Ivar;
	pub fn class_addMethod(cls: *mut Class, name: Sel, imp: Imp, types: *const c_char) -> bool;
	pub fn class_addIvar(cls: *mut Class, name: *const c_char, size: size_t, alignment: u8, types: *const c_char) -> bool;

	pub fn objc_allocateClassPair(superclass: *const Class, name: *const c_char, extraBytes: size_t) -> *mut Class;
	pub fn objc_disposeClassPair(cls: *mut Class);
	pub fn objc_registerClassPair(cls: *mut Class);

	pub fn object_getClass(obj: *const Object) -> *const Class;

	pub fn objc_getClassList(buffer: *mut *const Class, bufferLen: c_int) -> c_int;
	pub fn objc_copyClassList(outCount: *mut c_uint) -> *mut *const Class;
	pub fn objc_getClass(name: *const c_char) -> *const Class;

	pub fn ivar_getName(ivar: *const Ivar) -> *const c_char;
	pub fn ivar_getOffset(ivar: *const Ivar) -> ptrdiff_t;
	pub fn ivar_getTypeEncoding(ivar: *const Ivar) -> *const c_char;

	pub fn objc_msgSend(obj: *mut Object, op: Sel, ...) -> *mut Object;

	pub fn method_getName(method: *const Method) -> Sel;
	pub fn method_getImplementation(method: *const Method) -> Imp;
	pub fn method_getTypeEncoding(method: *const Method) -> *const c_char;
	pub fn method_copyReturnType(method: *const Method) -> *mut c_char;
	pub fn method_copyArgumentType(method: *const Method, index: c_uint) -> *mut c_char;
	pub fn method_getNumberOfArguments(method: *const Method) -> c_uint;
	pub fn method_setImplementation(method: *mut Method, imp: Imp) -> Imp;
	pub fn method_exchangeImplementations(m1: *mut Method, m2: *mut Method);
}

impl Sel {
	/// Registers a method with the Objective-C runtime system,
	/// maps the method name to a selector, and returns the selector value.
	pub fn register(name: &str) -> Sel {
		name.with_c_str(|name| unsafe {
			sel_registerName(name)
		})
	}

	/// Returns the name of the method specified by self.
	pub fn name(&self) -> &str {
		unsafe {
			let name = sel_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

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

impl Eq for Sel { }

impl Clone for Sel {
	fn clone(&self) -> Sel { *self }
}

impl Ivar {
	/// Returns the name of self.
	pub fn name(&self) -> &str {
		unsafe {
			let name = ivar_getName(self);
			c_str_to_static_slice(name)
		}
	}

	/// Returns the offset of self.
	pub fn offset(&self) -> int {
		let offset = unsafe {
			ivar_getOffset(self)
		};
		offset as int
	}

	/// Returns the type string of self.
	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = ivar_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}
}

impl Method {
	/// Returns the name of self.
	pub fn name(&self) -> Sel {
		unsafe {
			method_getName(self)
		}
	}

	/// Returns a string describing self's parameter and return types.
	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = method_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}

	/// Returns a string describing self's return type.
	pub fn return_type(&self) -> CString {
		unsafe {
			let encoding = method_copyReturnType(self);
			CString::new(encoding as *const _, true)
		}
	}

	/// Returns a string describing a single parameter type of self, or
	/// None if self has no parameter at the given index.
	pub fn argument_type(&self, index: uint) -> Option<CString> {
		unsafe {
			let encoding = method_copyArgumentType(self, index as c_uint);
			if encoding.is_null() {
				None
			} else {
				Some(CString::new(encoding as *const _, true))
			}
		}
	}

	/// Returns the number of arguments accepted by self.
	pub fn arguments_count(&self) -> uint {
		unsafe {
			method_getNumberOfArguments(self) as uint
		}
	}

	/// Returns the implementation of self.
	pub fn implementation(&self) -> Imp {
		unsafe {
			method_getImplementation(self)
		}
	}

	/// Sets the implementation of self.
	/// Unsafe because the caller must ensure the implementation has the
	/// correct self, return, and argument types for the method.
	pub unsafe fn set_implementation(&mut self, imp: Imp) -> Imp {
		method_setImplementation(self, imp)
	}

	/// Exchanges the implementations of self with another `Method`.
	/// Unsafe because the caller must ensure the two methods have the same
	/// self, return, and argument types.
	pub unsafe fn exchange_implementation(&mut self, other: &mut Method) {
		method_exchangeImplementations(self, other);
	}
}

impl Class {
	pub fn get(name: &str) -> Option<&'static Class> {
		name.with_c_str(|name| unsafe {
			objc_getClass(name).as_ref()
		})
	}

	pub fn classes() -> CVec<&'static Class> {
		unsafe {
			let mut count: c_uint = 0;
			let classes = objc_copyClassList(&mut count);
			CVec::new_with_dtor(classes as *mut _, count as uint, proc() {
				libc::free(classes as *mut c_void);
			})
		}
	}

	pub fn classes_count() -> uint {
		unsafe {
			objc_getClassList(RawPtr::null(), 0) as uint
		}
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = class_getName(self);
			c_str_to_static_slice(name)
		}
	}

	pub fn instance_size(&self) -> uint {
		unsafe {
			class_getInstanceSize(self) as uint
		}
	}

	pub fn instance_method(&self, sel: Sel) -> Option<&Method> {
		unsafe {
			class_getInstanceMethod(self, sel).as_ref()
		}
	}

	pub fn instance_variable(&self, name: &str) -> Option<&Ivar> {
		name.with_c_str(|name| unsafe {
			class_getInstanceVariable(self, name).as_ref()
		})
	}

	pub fn instance_methods(&self) -> CVec<&Method> {
		unsafe {
			let mut count: c_uint = 0;
			let methods = class_copyMethodList(self, &mut count);
			CVec::new_with_dtor(methods as *mut _, count as uint, proc() {
				libc::free(methods as *mut c_void);
			})
		}

	}

	pub fn instance_variables(&self) -> CVec<&Ivar> {
		unsafe {
			let mut count: c_uint = 0;
			let ivars = class_copyIvarList(self, &mut count);
			CVec::new_with_dtor(ivars as *mut _, count as uint, proc() {
				libc::free(ivars as *mut c_void);
			})
		}
	}
}

impl PartialEq for Class {
	fn eq(&self, other: &Class) -> bool {
		self as *const Class == other as *const Class
	}
}

impl Eq for Class { }

impl Object {
	pub fn class(&self) -> &'static Class {
		unsafe {
			&*object_getClass(self)
		}
	}

	pub unsafe fn get_ivar<T: Encode>(&self, name: &str) -> &T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *const Object;
				(self_ptr as *const u8).offset(offset) as *const T
			}
			None => panic!("Ivar {} not found on class {}", name, cls.name()),
		};
		&*ptr
	}

	pub unsafe fn get_mut_ivar<T: Encode>(&mut self, name: &str) -> &mut T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *mut Object;
				(self_ptr as *mut u8).offset(offset) as *mut T
			}
			None => panic!("Ivar {} not found on class {}", name, cls.name()),
		};
		&mut *ptr
	}

	pub unsafe fn set_ivar<T: Encode>(&mut self, name: &str, value: T) {
		*self.get_mut_ivar::<T>(name) = value;
	}
}

#[cfg(test)]
mod tests {
	use std::mem;
	use super::{Class, Sel};

	#[test]
	fn test_ivar() {
		let cls = Class::get("NSObject").unwrap();
		let ivar = cls.instance_variable("isa").unwrap();
		assert!(ivar.name() == "isa");
		assert!(ivar.type_encoding() == "#");
		assert!(ivar.offset() == 0);

		let ivars = cls.instance_variables();
		assert!(ivars.len() > 0);
	}

	#[test]
	fn test_method() {
		let cls = Class::get("NSObject").unwrap();
		let sel = Sel::register("description");
		let method = cls.instance_method(sel).unwrap();
		assert!(method.name().name() == "description");
		assert!(method.type_encoding() != "");
		assert!(method.arguments_count() == 2);
		assert!(method.return_type().as_bytes_no_nul() == "@".as_bytes());
		assert!(method.argument_type(1).unwrap().as_bytes_no_nul() ==
			":".as_bytes());

		let methods = cls.instance_methods();
		assert!(methods.len() > 0);
	}

	#[test]
	fn test_class() {
		let cls = Class::get("NSObject").unwrap();
		assert!(cls.name() == "NSObject");
		assert!(cls.instance_size() == mem::size_of::<*const Class>());
	}

	#[test]
	fn test_classes() {
		let classes_count = Class::classes_count();
		assert!(classes_count > 0);

		let classes = Class::classes();
		assert!(classes.len() == classes_count);
	}

	#[test]
	fn test_object() {
		let cls = Class::get("NSObject").unwrap();
		let obj = unsafe {
			let obj = msg_send![cls alloc];
			let obj = msg_send![obj init];
			&*obj
		};
		assert!(obj.class() == cls);
		unsafe {
			msg_send![obj release];
		}
	}
}
<commit_msg>Add runtime documentation for Class and Object.<commit_after>//! A Rust interface for the functionality of the Objective-C runtime.
//!
//! For more information on foreign functions, see Apple's documentation:
//! https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html

use std::c_str::CString;
use std::c_vec::CVec;
use std::kinds::marker::NoCopy;
use std::str::raw::c_str_to_static_slice;
use libc::{c_char, c_int, c_uint, c_void, ptrdiff_t, size_t};
use libc;

use {encode, Encode};

/// A type that represents a method selector.
#[repr(C)]
pub struct Sel {
	ptr: *const c_void,
}

/// A type that represents an instance variable.
pub struct Ivar {
	nocopy: NoCopy,
}

/// A type that represents a method in a class definition.
pub struct Method {
	nocopy: NoCopy,
}

/// A type that represents an Objective-C class.
pub struct Class {
	nocopy: NoCopy,
}

/// A type that represents an instance of a class.
pub struct Object {
	nocopy: NoCopy,
}

/// A pointer to the start of a method implementation.
pub type Imp = extern fn(*mut Object, Sel, ...) -> *mut Object;

#[allow(improper_ctypes)]
#[link(name = "Foundation", kind = "framework")]
extern {
	pub fn sel_registerName(name: *const c_char) -> Sel;
	pub fn sel_getName(sel: Sel) -> *const c_char;

	pub fn class_getName(cls: *const Class) -> *const c_char;
	pub fn class_getInstanceSize(cls: *const Class) -> size_t;
	pub fn class_getInstanceMethod(cls: *const Class, sel: Sel) -> *const Method;
	pub fn class_getInstanceVariable(cls: *const Class, name: *const c_char) -> *const Ivar;
	pub fn class_copyMethodList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Method;
	pub fn class_copyIvarList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Ivar;
	pub fn class_addMethod(cls: *mut Class, name: Sel, imp: Imp, types: *const c_char) -> bool;
	pub fn class_addIvar(cls: *mut Class, name: *const c_char, size: size_t, alignment: u8, types: *const c_char) -> bool;

	pub fn objc_allocateClassPair(superclass: *const Class, name: *const c_char, extraBytes: size_t) -> *mut Class;
	pub fn objc_disposeClassPair(cls: *mut Class);
	pub fn objc_registerClassPair(cls: *mut Class);

	pub fn object_getClass(obj: *const Object) -> *const Class;

	pub fn objc_getClassList(buffer: *mut *const Class, bufferLen: c_int) -> c_int;
	pub fn objc_copyClassList(outCount: *mut c_uint) -> *mut *const Class;
	pub fn objc_getClass(name: *const c_char) -> *const Class;

	pub fn ivar_getName(ivar: *const Ivar) -> *const c_char;
	pub fn ivar_getOffset(ivar: *const Ivar) -> ptrdiff_t;
	pub fn ivar_getTypeEncoding(ivar: *const Ivar) -> *const c_char;

	pub fn objc_msgSend(obj: *mut Object, op: Sel, ...) -> *mut Object;

	pub fn method_getName(method: *const Method) -> Sel;
	pub fn method_getImplementation(method: *const Method) -> Imp;
	pub fn method_getTypeEncoding(method: *const Method) -> *const c_char;
	pub fn method_copyReturnType(method: *const Method) -> *mut c_char;
	pub fn method_copyArgumentType(method: *const Method, index: c_uint) -> *mut c_char;
	pub fn method_getNumberOfArguments(method: *const Method) -> c_uint;
	pub fn method_setImplementation(method: *mut Method, imp: Imp) -> Imp;
	pub fn method_exchangeImplementations(m1: *mut Method, m2: *mut Method);
}

impl Sel {
	/// Registers a method with the Objective-C runtime system,
	/// maps the method name to a selector, and returns the selector value.
	pub fn register(name: &str) -> Sel {
		name.with_c_str(|name| unsafe {
			sel_registerName(name)
		})
	}

	/// Returns the name of the method specified by self.
	pub fn name(&self) -> &str {
		unsafe {
			let name = sel_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

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

impl Eq for Sel { }

impl Clone for Sel {
	fn clone(&self) -> Sel { *self }
}

impl Ivar {
	/// Returns the name of self.
	pub fn name(&self) -> &str {
		unsafe {
			let name = ivar_getName(self);
			c_str_to_static_slice(name)
		}
	}

	/// Returns the offset of self.
	pub fn offset(&self) -> int {
		let offset = unsafe {
			ivar_getOffset(self)
		};
		offset as int
	}

	/// Returns the type string of self.
	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = ivar_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}
}

impl Method {
	/// Returns the name of self.
	pub fn name(&self) -> Sel {
		unsafe {
			method_getName(self)
		}
	}

	/// Returns a string describing self's parameter and return types.
	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = method_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}

	/// Returns a string describing self's return type.
	pub fn return_type(&self) -> CString {
		unsafe {
			let encoding = method_copyReturnType(self);
			CString::new(encoding as *const _, true)
		}
	}

	/// Returns a string describing a single parameter type of self, or
	/// `None` if self has no parameter at the given index.
	pub fn argument_type(&self, index: uint) -> Option<CString> {
		unsafe {
			let encoding = method_copyArgumentType(self, index as c_uint);
			if encoding.is_null() {
				None
			} else {
				Some(CString::new(encoding as *const _, true))
			}
		}
	}

	/// Returns the number of arguments accepted by self.
	pub fn arguments_count(&self) -> uint {
		unsafe {
			method_getNumberOfArguments(self) as uint
		}
	}

	/// Returns the implementation of self.
	pub fn implementation(&self) -> Imp {
		unsafe {
			method_getImplementation(self)
		}
	}

	/// Sets the implementation of self.
	/// Unsafe because the caller must ensure the implementation has the
	/// correct self, return, and argument types for the method.
	pub unsafe fn set_implementation(&mut self, imp: Imp) -> Imp {
		method_setImplementation(self, imp)
	}

	/// Exchanges the implementations of self with another `Method`.
	/// Unsafe because the caller must ensure the two methods have the same
	/// self, return, and argument types.
	pub unsafe fn exchange_implementation(&mut self, other: &mut Method) {
		method_exchangeImplementations(self, other);
	}
}

impl Class {
	/// Returns the class definition of a specified class, or `None` if the
	/// class is not registered with the Objective-C runtime.
	pub fn get(name: &str) -> Option<&'static Class> {
		name.with_c_str(|name| unsafe {
			objc_getClass(name).as_ref()
		})
	}

	/// Obtains the list of registered class definitions.
	pub fn classes() -> CVec<&'static Class> {
		unsafe {
			let mut count: c_uint = 0;
			let classes = objc_copyClassList(&mut count);
			CVec::new_with_dtor(classes as *mut _, count as uint, proc() {
				libc::free(classes as *mut c_void);
			})
		}
	}

	/// Returns the total number of registered classes.
	pub fn classes_count() -> uint {
		unsafe {
			objc_getClassList(RawPtr::null(), 0) as uint
		}
	}

	/// Returns the name of self.
	pub fn name(&self) -> &str {
		unsafe {
			let name = class_getName(self);
			c_str_to_static_slice(name)
		}
	}

	/// Returns the size of instances of self.
	pub fn instance_size(&self) -> uint {
		unsafe {
			class_getInstanceSize(self) as uint
		}
	}

	/// Returns a specified instance method for self, or `None` if self and
	/// its superclasses do not contain an instance method with the
	/// specified selector.
	pub fn instance_method(&self, sel: Sel) -> Option<&Method> {
		unsafe {
			class_getInstanceMethod(self, sel).as_ref()
		}
	}

	/// Returns the ivar for a specified instance variable of self, or `None`
	/// if self has no ivar with the given name.
	pub fn instance_variable(&self, name: &str) -> Option<&Ivar> {
		name.with_c_str(|name| unsafe {
			class_getInstanceVariable(self, name).as_ref()
		})
	}

	/// Describes the instance methods implemented by self.
	pub fn instance_methods(&self) -> CVec<&Method> {
		unsafe {
			let mut count: c_uint = 0;
			let methods = class_copyMethodList(self, &mut count);
			CVec::new_with_dtor(methods as *mut _, count as uint, proc() {
				libc::free(methods as *mut c_void);
			})
		}

	}

	/// Describes the instance variables declared by self.
	pub fn instance_variables(&self) -> CVec<&Ivar> {
		unsafe {
			let mut count: c_uint = 0;
			let ivars = class_copyIvarList(self, &mut count);
			CVec::new_with_dtor(ivars as *mut _, count as uint, proc() {
				libc::free(ivars as *mut c_void);
			})
		}
	}
}

impl PartialEq for Class {
	fn eq(&self, other: &Class) -> bool {
		self as *const Class == other as *const Class
	}
}

impl Eq for Class { }

impl Object {
	/// Returns the class of self.
	pub fn class(&self) -> &'static Class {
		unsafe {
			&*object_getClass(self)
		}
	}

	/// Returns a reference to the ivar of self with the given name.
	/// Panics if self has no ivar with the given name.
	/// Unsafe because the caller must ensure that the ivar is actually
	/// of type `T`.
	pub unsafe fn get_ivar<T: Encode>(&self, name: &str) -> &T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *const Object;
				(self_ptr as *const u8).offset(offset) as *const T
			}
			None => panic!("Ivar {} not found on class {}", name, cls.name()),
		};
		&*ptr
	}

	/// Returns a mutable reference to the ivar of self with the given name.
	/// Panics if self has no ivar with the given name.
	/// Unsafe because the caller must ensure that the ivar is actually
	/// of type `T`.
	pub unsafe fn get_mut_ivar<T: Encode>(&mut self, name: &str) -> &mut T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *mut Object;
				(self_ptr as *mut u8).offset(offset) as *mut T
			}
			None => panic!("Ivar {} not found on class {}", name, cls.name()),
		};
		&mut *ptr
	}

	/// Sets the value of the ivar of self with the given name.
	/// Panics if self has no ivar with the given name.
	/// Unsafe because the caller must ensure that the ivar is actually
	/// of type `T`.
	pub unsafe fn set_ivar<T: Encode>(&mut self, name: &str, value: T) {
		*self.get_mut_ivar::<T>(name) = value;
	}
}

#[cfg(test)]
mod tests {
	use std::mem;
	use super::{Class, Sel};

	#[test]
	fn test_ivar() {
		let cls = Class::get("NSObject").unwrap();
		let ivar = cls.instance_variable("isa").unwrap();
		assert!(ivar.name() == "isa");
		assert!(ivar.type_encoding() == "#");
		assert!(ivar.offset() == 0);

		let ivars = cls.instance_variables();
		assert!(ivars.len() > 0);
	}

	#[test]
	fn test_method() {
		let cls = Class::get("NSObject").unwrap();
		let sel = Sel::register("description");
		let method = cls.instance_method(sel).unwrap();
		assert!(method.name().name() == "description");
		assert!(method.type_encoding() != "");
		assert!(method.arguments_count() == 2);
		assert!(method.return_type().as_bytes_no_nul() == "@".as_bytes());
		assert!(method.argument_type(1).unwrap().as_bytes_no_nul() ==
			":".as_bytes());

		let methods = cls.instance_methods();
		assert!(methods.len() > 0);
	}

	#[test]
	fn test_class() {
		let cls = Class::get("NSObject").unwrap();
		assert!(cls.name() == "NSObject");
		assert!(cls.instance_size() == mem::size_of::<*const Class>());
	}

	#[test]
	fn test_classes() {
		let classes_count = Class::classes_count();
		assert!(classes_count > 0);

		let classes = Class::classes();
		assert!(classes.len() == classes_count);
	}

	#[test]
	fn test_object() {
		let cls = Class::get("NSObject").unwrap();
		let obj = unsafe {
			let obj = msg_send![cls alloc];
			let obj = msg_send![obj init];
			&*obj
		};
		assert!(obj.class() == cls);
		unsafe {
			msg_send![obj release];
		}
	}
}
<|endoftext|>


<commit_before>//! `coresimd`

#[macro_use]
mod macros;

mod simd;

/// Platform dependent vendor intrinsics.
///
/// This documentation is for the version of this module in the `coresimd`
/// crate, but you probably want to use the [`stdsimd` crate][stdsimd] which
/// should have more complete documentation.
///
/// [stdsimd]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/arch/index.html
///
/// Also note that while this module may appear to contains the intrinsics for
/// only one platform it actually contains intrinsics for multiple platforms
/// compiled in conditionally. For other platforms of stdsimd see:
///
/// * [`x86`]
/// * [`x86_64`]
/// * [`arm`]
/// * [`aarch64`]
/// * [`mips`]
/// * [`mips64`]
/// * [`PowerPC`]
/// * [`PowerPC64`]
/// * [`NVPTX`]
/// * [`wasm32`]
///
/// [`x86`]: https://rust-lang-nursery.github.io/stdsimd/x86/stdsimd/arch/index.html
/// [`x86_64`]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/arch/index.html
/// [`arm`]: https://rust-lang-nursery.github.io/stdsimd/arm/stdsimd/arch/index.html
/// [`aarch64`]: https://rust-lang-nursery.github.io/stdsimd/aarch64/stdsimd/arch/index.html
/// [`mips`]: https://rust-lang-nursery.github.io/stdsimd/mips/stdsimd/arch/index.html
/// [`mips64`]: https://rust-lang-nursery.github.io/stdsimd/mips64/stdsimd/arch/index.html
/// [`PowerPC`]: https://rust-lang-nursery.github.io/stdsimd/powerpc/stdsimd/arch/index.html
/// [`PowerPC64`]: https://rust-lang-nursery.github.io/stdsimd/powerpc64/stdsimd/arch/index.html
/// [`NVPTX`]: https://rust-lang-nursery.github.io/stdsimd/nvptx/stdsimd/arch/index.html
/// [`wasm32`]: https://rust-lang-nursery.github.io/stdsimd/wasm32/stdsimd/arch/index.html
#[stable(feature = "simd_arch", since = "1.27.0")]
pub mod arch {
    /// Platform-specific intrinsics for the `x86` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86", dox))]
    #[doc(cfg(target_arch = "x86"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86::*;
    }

    /// Platform-specific intrinsics for the `x86_64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86_64", dox))]
    #[doc(cfg(target_arch = "x86_64"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86_64 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86::*;
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86_64::*;
    }

    /// Platform-specific intrinsics for the `arm` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "arm", dox))]
    #[doc(cfg(target_arch = "arm"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod arm {
        pub use coresimd::arm::*;
    }

    /// Platform-specific intrinsics for the `aarch64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "aarch64", dox))]
    #[doc(cfg(target_arch = "aarch64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod aarch64 {
        pub use coresimd::aarch64::*;
        pub use coresimd::arm::*;
    }

    /// Platform-specific intrinsics for the `wasm32` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "wasm32", dox))]
    #[doc(cfg(target_arch = "mips"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod wasm32 {
        pub use coresimd::wasm32::*;
    }

    /// Platform-specific intrinsics for the `mips` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips", dox))]
    #[doc(cfg(target_arch = "mips"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips {
        pub use coresimd::mips::*;
    }

    /// Platform-specific intrinsics for the `mips64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips64", dox))]
    #[doc(cfg(target_arch = "mips64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips64 {
        pub use coresimd::mips::*;
    }

    /// Platform-specific intrinsics for the `PowerPC` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc", dox))]
    #[doc(cfg(target_arch = "powerpc"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc {
        pub use coresimd::powerpc::*;
    }

    /// Platform-specific intrinsics for the `PowerPC64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc64", dox))]
    #[doc(cfg(target_arch = "powerpc64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc64 {
        pub use coresimd::powerpc64::*;
    }

    /// Platform-specific intrinsics for the `NVPTX` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "nvptx", target_arch = "nvptx64", dox))]
    #[doc(cfg(any(target_arch = "nvptx", target_arch = "nvptx64")))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod nvptx {
        pub use coresimd::nvptx::*;
    }
}

mod simd_llvm;

#[cfg(any(target_arch = "x86", target_arch = "x86_64", dox))]
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
mod x86;
#[cfg(any(target_arch = "x86_64", dox))]
#[doc(cfg(target_arch = "x86_64"))]
mod x86_64;

#[cfg(any(target_arch = "aarch64", dox))]
#[doc(cfg(target_arch = "aarch64"))]
mod aarch64;
#[cfg(any(target_arch = "arm", target_arch = "aarch64", dox))]
#[doc(cfg(any(target_arch = "arm", target_arch = "aarch64")))]
mod arm;

#[cfg(any(target_arch = "wasm32", dox))]
#[doc(cfg(target_arch = "wasm32"))]
mod wasm32;

#[cfg(any(target_arch = "mips", target_arch = "mips64", dox))]
#[doc(cfg(any(target_arch = "mips", target_arch = "mips64")))]
mod mips;

#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64", dox))]
#[doc(cfg(any(target_arch = "powerpc", target_arch = "powerpc64")))]
mod powerpc;

#[cfg(any(target_arch = "powerpc64", dox))]
#[doc(cfg(target_arch = "powerpc64"))]
mod powerpc64;

#[cfg(any(target_arch = "nvptx", target_arch = "nvptx64", dox))]
#[doc(cfg(any(target_arch = "nvptx", target_arch = "nvptx64")))]
mod nvptx;
<commit_msg>Fix a copy/paste error on wasm32<commit_after>//! `coresimd`

#[macro_use]
mod macros;

mod simd;

/// Platform dependent vendor intrinsics.
///
/// This documentation is for the version of this module in the `coresimd`
/// crate, but you probably want to use the [`stdsimd` crate][stdsimd] which
/// should have more complete documentation.
///
/// [stdsimd]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/arch/index.html
///
/// Also note that while this module may appear to contains the intrinsics for
/// only one platform it actually contains intrinsics for multiple platforms
/// compiled in conditionally. For other platforms of stdsimd see:
///
/// * [`x86`]
/// * [`x86_64`]
/// * [`arm`]
/// * [`aarch64`]
/// * [`mips`]
/// * [`mips64`]
/// * [`PowerPC`]
/// * [`PowerPC64`]
/// * [`NVPTX`]
/// * [`wasm32`]
///
/// [`x86`]: https://rust-lang-nursery.github.io/stdsimd/x86/stdsimd/arch/index.html
/// [`x86_64`]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/arch/index.html
/// [`arm`]: https://rust-lang-nursery.github.io/stdsimd/arm/stdsimd/arch/index.html
/// [`aarch64`]: https://rust-lang-nursery.github.io/stdsimd/aarch64/stdsimd/arch/index.html
/// [`mips`]: https://rust-lang-nursery.github.io/stdsimd/mips/stdsimd/arch/index.html
/// [`mips64`]: https://rust-lang-nursery.github.io/stdsimd/mips64/stdsimd/arch/index.html
/// [`PowerPC`]: https://rust-lang-nursery.github.io/stdsimd/powerpc/stdsimd/arch/index.html
/// [`PowerPC64`]: https://rust-lang-nursery.github.io/stdsimd/powerpc64/stdsimd/arch/index.html
/// [`NVPTX`]: https://rust-lang-nursery.github.io/stdsimd/nvptx/stdsimd/arch/index.html
/// [`wasm32`]: https://rust-lang-nursery.github.io/stdsimd/wasm32/stdsimd/arch/index.html
#[stable(feature = "simd_arch", since = "1.27.0")]
pub mod arch {
    /// Platform-specific intrinsics for the `x86` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86", dox))]
    #[doc(cfg(target_arch = "x86"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86::*;
    }

    /// Platform-specific intrinsics for the `x86_64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86_64", dox))]
    #[doc(cfg(target_arch = "x86_64"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86_64 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86::*;
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86_64::*;
    }

    /// Platform-specific intrinsics for the `arm` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "arm", dox))]
    #[doc(cfg(target_arch = "arm"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod arm {
        pub use coresimd::arm::*;
    }

    /// Platform-specific intrinsics for the `aarch64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "aarch64", dox))]
    #[doc(cfg(target_arch = "aarch64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod aarch64 {
        pub use coresimd::aarch64::*;
        pub use coresimd::arm::*;
    }

    /// Platform-specific intrinsics for the `wasm32` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "wasm32", dox))]
    #[doc(cfg(target_arch = "wasm32"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod wasm32 {
        pub use coresimd::wasm32::*;
    }

    /// Platform-specific intrinsics for the `mips` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips", dox))]
    #[doc(cfg(target_arch = "mips"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips {
        pub use coresimd::mips::*;
    }

    /// Platform-specific intrinsics for the `mips64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips64", dox))]
    #[doc(cfg(target_arch = "mips64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips64 {
        pub use coresimd::mips::*;
    }

    /// Platform-specific intrinsics for the `PowerPC` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc", dox))]
    #[doc(cfg(target_arch = "powerpc"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc {
        pub use coresimd::powerpc::*;
    }

    /// Platform-specific intrinsics for the `PowerPC64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc64", dox))]
    #[doc(cfg(target_arch = "powerpc64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc64 {
        pub use coresimd::powerpc64::*;
    }

    /// Platform-specific intrinsics for the `NVPTX` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "nvptx", target_arch = "nvptx64", dox))]
    #[doc(cfg(any(target_arch = "nvptx", target_arch = "nvptx64")))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod nvptx {
        pub use coresimd::nvptx::*;
    }
}

mod simd_llvm;

#[cfg(any(target_arch = "x86", target_arch = "x86_64", dox))]
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
mod x86;
#[cfg(any(target_arch = "x86_64", dox))]
#[doc(cfg(target_arch = "x86_64"))]
mod x86_64;

#[cfg(any(target_arch = "aarch64", dox))]
#[doc(cfg(target_arch = "aarch64"))]
mod aarch64;
#[cfg(any(target_arch = "arm", target_arch = "aarch64", dox))]
#[doc(cfg(any(target_arch = "arm", target_arch = "aarch64")))]
mod arm;

#[cfg(any(target_arch = "wasm32", dox))]
#[doc(cfg(target_arch = "wasm32"))]
mod wasm32;

#[cfg(any(target_arch = "mips", target_arch = "mips64", dox))]
#[doc(cfg(any(target_arch = "mips", target_arch = "mips64")))]
mod mips;

#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64", dox))]
#[doc(cfg(any(target_arch = "powerpc", target_arch = "powerpc64")))]
mod powerpc;

#[cfg(any(target_arch = "powerpc64", dox))]
#[doc(cfg(target_arch = "powerpc64"))]
mod powerpc64;

#[cfg(any(target_arch = "nvptx", target_arch = "nvptx64", dox))]
#[doc(cfg(any(target_arch = "nvptx", target_arch = "nvptx64")))]
mod nvptx;
<|endoftext|>


<commit_before>#![crate_id="app"]
#![crate_type="rlib"]
#![no_std]
#![feature(globs, macro_rules, asm)]

extern crate zinc;
extern crate core;

#[cfg(mcu_lpc17xx)] use zinc::boards::mbed_lpc1768;
use zinc::hal::gpio::GPIOConf;
use zinc::hal::init::SysConf;
use zinc::hal::timer::{TimerConf, Timer};
use zinc::hal::uart::{UARTConf, None};
use zinc::hal::pin::map;
use zinc::drivers::chario::CharIO;
use zinc::os::task;
use zinc::os::debug;

#[cfg(mcu_lpc17xx)] use zinc::hal::lpc17xx;

struct Platform {
  configuration: SysConf,
  led1: GPIOConf,
  led2: GPIOConf,
  timer: TimerConf,
  uart: UARTConf,
}

#[cfg(mcu_lpc17xx)]
static platform: Platform = Platform {
  configuration: mbed_lpc1768::configuration,
  led1: mbed_lpc1768::led1,
  led2: mbed_lpc1768::led4,
  timer: TimerConf {
    timer: lpc17xx::timer::Timer1,
    counter: 25,
    divisor: 4,
  },
  uart: UARTConf {
    peripheral: lpc17xx::uart::UART0,
    baudrate: 115200,
    word_len: 8,
    parity: None,
    stop_bits: 1,

    tx: map::port0::pin2::TXD0,
    rx: map::port0::pin3::RXD0,
  },
};

fn task(arg: u32) {
  let timer = &platform.timer.setup() as &Timer;
  timer.wait(1);

  let d = debug::io();
  d.puts("task "); d.puti(arg); d.puts(" started\n");

  loop {
    timer.wait(2);
    d.puts("running in task "); d.puti(arg); d.puts("\n");
  }
}

fn main_task(arg: u32) {
  let timer = &platform.timer.setup() as &Timer;
  let d = debug::io();
  d.puts("task "); d.puti(arg); d.puts(" started\n");

  task::define_task(task, 1, 512, false);
  task::define_task(task, 2, 512, false);

  loop {
    timer.wait(2);
    d.puts("running in main task\n");
  }
}

#[no_split_stack]
pub fn main() {
  platform.configuration.setup();
  debug::setup(&platform.uart);

  task::setup(main_task, 512);
}
<commit_msg>Removed core crate reference from app_sched.<commit_after>#![crate_id="app"]
#![crate_type="rlib"]
#![no_std]
#![feature(globs, macro_rules, asm)]

extern crate zinc;

#[cfg(mcu_lpc17xx)] use zinc::boards::mbed_lpc1768;
use zinc::hal::gpio::GPIOConf;
use zinc::hal::init::SysConf;
use zinc::hal::timer::{TimerConf, Timer};
use zinc::hal::uart::{UARTConf, None};
use zinc::hal::pin::map;
use zinc::drivers::chario::CharIO;
use zinc::os::task;
use zinc::os::debug;

#[cfg(mcu_lpc17xx)] use zinc::hal::lpc17xx;

struct Platform {
  configuration: SysConf,
  led1: GPIOConf,
  led2: GPIOConf,
  timer: TimerConf,
  uart: UARTConf,
}

#[cfg(mcu_lpc17xx)]
static platform: Platform = Platform {
  configuration: mbed_lpc1768::configuration,
  led1: mbed_lpc1768::led1,
  led2: mbed_lpc1768::led4,
  timer: TimerConf {
    timer: lpc17xx::timer::Timer1,
    counter: 25,
    divisor: 4,
  },
  uart: UARTConf {
    peripheral: lpc17xx::uart::UART0,
    baudrate: 115200,
    word_len: 8,
    parity: None,
    stop_bits: 1,

    tx: map::port0::pin2::TXD0,
    rx: map::port0::pin3::RXD0,
  },
};

fn task(arg: u32) {
  let timer = &platform.timer.setup() as &Timer;
  timer.wait(1);

  let d = debug::io();
  d.puts("task "); d.puti(arg); d.puts(" started\n");

  loop {
    timer.wait(2);
    d.puts("running in task "); d.puti(arg); d.puts("\n");
  }
}

fn main_task(arg: u32) {
  let timer = &platform.timer.setup() as &Timer;
  let d = debug::io();
  d.puts("task "); d.puti(arg); d.puts(" started\n");

  task::define_task(task, 1, 512, false);
  task::define_task(task, 2, 512, false);

  loop {
    timer.wait(2);
    d.puts("running in main task\n");
  }
}

#[no_split_stack]
pub fn main() {
  platform.configuration.setup();
  debug::setup(&platform.uart);

  task::setup(main_task, 512);
}
<|endoftext|>


<commit_before>
pub use selector::*;
pub use theme::*;

pub mod prelude;
mod selector;
mod theme;
<commit_msg>Add description to theme crate.<commit_after>/*!

This crate provides functions to load a css files as theme and access it properties with
selectors.

This crate depends on the orbtk_utils crate.

# Example

Basic usage of the tree:

```rust,no_run

use orbtk_css_engine::prelude::*;

let mut theme = Theme::create_from_path("theme.css").build();
let selector = Selector::from("button");
let background = theme.brush("background", &selector);

```

 */

pub use selector::*;
pub use theme::*;

pub mod prelude;
mod selector;
mod theme;
<|endoftext|>


<commit_before>extern crate gcc;
extern crate regex;

use std::process::Command;
use std::env;
use regex::Regex;

fn main() {
    // 1. Build the object file from source using node-gyp.
    build_object_file();

    // 2. Link the library from the object file using gcc.
    link_library();
}

#[cfg(unix)]
fn npm() -> Command {
    Command::new("npm")
}

#[cfg(windows)]
fn npm() -> Command {
    let mut cmd = Command::new("cmd.exe");
    cmd.args(&["/C", "npm"]);
    cmd
}

// The node-gyp output includes platform information in a string
// that looks like:
//
//     gyp info using node@8.3.0 | win32 | x64
#[cfg(windows)]
fn parse_node_arch(node_gyp_output: &str) -> String {
    let version_regex = Regex::new(r"node@(?P<version>\d+\.\d+\.\d+)\s+\|\s+(?P<platform>\w+)\s+\|\s(?P<arch>ia32|x64)").unwrap();
    let captures = version_regex.captures(&node_gyp_output).unwrap();
    String::from(&captures["arch"])
}

// The node-gyp output includes the root directory of shared resources
// for the Node installation in a string that looks like:
//
//     '-Dnode_root_dir=C:\\Users\\dherman\\.node-gyp\\8.3.0'
#[cfg(windows)]
fn parse_node_root_dir(node_gyp_output: &str) -> &str {
    let node_root_dir_flag_pattern = "'-Dnode_root_dir=";
    let node_root_dir_start_index = node_gyp_output
        .find(node_root_dir_flag_pattern)
        .map(|i| i + node_root_dir_flag_pattern.len())
        .expect("Couldn't find node_root_dir in node-gyp output.");
    let node_root_dir_end_index = node_gyp_output[node_root_dir_start_index..].find("'").unwrap() + node_root_dir_start_index;
    &node_gyp_output[node_root_dir_start_index..node_root_dir_end_index]
}

// The node-gyp output includes the name of the shared Node library file.
// In NPM versions <= v5.0.3, this was just the filename by itself, e.g.:
//
//     '-Dnode_lib_file=node.lib'
//
// In NPM versions >= v5.3.0, this was a templated absolute path with a
// reference to a gyp variable, e.g.:
//
//     '-Dnode_lib_file=C:\\Users\\dherman\\.node-gyp\\8.3.0\\<(target_arch)\\node.lib'
//
// Either way, we simply extract the value here. The `neon-build` crate
// processes it further.
#[cfg(windows)]
fn parse_node_lib_file(node_gyp_output: &str) -> &str {
    let node_lib_file_flag_pattern = "'-Dnode_lib_file=";
    let node_lib_file_start_index = node_gyp_output
        .find(node_lib_file_flag_pattern)
        .map(|i| i + node_lib_file_flag_pattern.len())
        .expect("Couldn't find node_lib_file in node-gyp output.");
    let node_lib_file_end_index = node_gyp_output[node_lib_file_start_index..].find("'").unwrap() + node_lib_file_start_index;
    &node_gyp_output[node_lib_file_start_index..node_lib_file_end_index]
}

fn build_object_file() {
    if cfg!(windows) {
        // Downcase all the npm environment variables to ensure they are read by node-gyp.
        for (key, value) in env::vars() {
            if key.starts_with("NPM_CONFIG") {
                env::remove_var(&key);
                env::set_var(key.to_lowercase(), value);
            }
        }
    }

    // Ensure that all package.json dependencies and dev dependencies are installed.
    npm().args(&["install", "--silent"]).status().ok().expect("Failed to run \"npm install\" for neon-runtime!");

    // Run `node-gyp configure` in verbose mode to read node_root_dir on Windows.
    let output = npm()
        .args(&["run", if debug() { "configure-debug" } else { "configure-release" }])
        .output()
        .expect("Failed to run \"node-gyp configure\" for neon-runtime!");

    if cfg!(windows) {
        let node_gyp_output = String::from_utf8_lossy(&output.stderr);
        println!("cargo:node_arch={}", parse_node_arch(&node_gyp_output));
        println!("cargo:node_root_dir={}", parse_node_root_dir(&node_gyp_output));
        println!("cargo:node_lib_file={}", parse_node_lib_file(&node_gyp_output));
    }

    // Run `node-gyp build`.
    npm()
        .args(&["run", if debug() { "build-debug" } else { "build-release" }])
        .status()
        .ok()
        .expect("Failed to run \"node-gyp build\" for neon-runtime!");
}

// Link the built object file into a static library.
fn link_library() {
    let configuration = if debug() { "Debug" } else { "Release" };
    let object_path = if cfg!(unix) {
        format!("build/{}/obj.target/neon/src/neon.o", configuration)
    } else {
        format!("build\\{}\\obj\\neon\\neon.obj", configuration)
    };

    gcc::Build::new().object(object_path).compile("libneon.a");
}

fn debug() -> bool {
    match env::var("DEBUG") {
        Ok(s) => s == "true",
        Err(_) => false
    }
}
<commit_msg>node-gyp parsing functions need to be in all configurations even though dynamically they'll only be used by windows<commit_after>extern crate gcc;
extern crate regex;

use std::process::Command;
use std::env;
use regex::Regex;

fn main() {
    // 1. Build the object file from source using node-gyp.
    build_object_file();

    // 2. Link the library from the object file using gcc.
    link_library();
}

#[cfg(unix)]
fn npm() -> Command {
    Command::new("npm")
}

#[cfg(windows)]
fn npm() -> Command {
    let mut cmd = Command::new("cmd.exe");
    cmd.args(&["/C", "npm"]);
    cmd
}

// The node-gyp output includes platform information in a string
// that looks like:
//
//     gyp info using node@8.3.0 | win32 | x64
fn parse_node_arch(node_gyp_output: &str) -> String {
    let version_regex = Regex::new(r"node@(?P<version>\d+\.\d+\.\d+)\s+\|\s+(?P<platform>\w+)\s+\|\s(?P<arch>ia32|x64)").unwrap();
    let captures = version_regex.captures(&node_gyp_output).unwrap();
    String::from(&captures["arch"])
}

// The node-gyp output includes the root directory of shared resources
// for the Node installation in a string that looks like:
//
//     '-Dnode_root_dir=C:\\Users\\dherman\\.node-gyp\\8.3.0'
fn parse_node_root_dir(node_gyp_output: &str) -> &str {
    let node_root_dir_flag_pattern = "'-Dnode_root_dir=";
    let node_root_dir_start_index = node_gyp_output
        .find(node_root_dir_flag_pattern)
        .map(|i| i + node_root_dir_flag_pattern.len())
        .expect("Couldn't find node_root_dir in node-gyp output.");
    let node_root_dir_end_index = node_gyp_output[node_root_dir_start_index..].find("'").unwrap() + node_root_dir_start_index;
    &node_gyp_output[node_root_dir_start_index..node_root_dir_end_index]
}

// The node-gyp output includes the name of the shared Node library file.
// In NPM versions <= v5.0.3, this was just the filename by itself, e.g.:
//
//     '-Dnode_lib_file=node.lib'
//
// In NPM versions >= v5.3.0, this was a templated absolute path with a
// reference to a gyp variable, e.g.:
//
//     '-Dnode_lib_file=C:\\Users\\dherman\\.node-gyp\\8.3.0\\<(target_arch)\\node.lib'
//
// Either way, we simply extract the value here. The `neon-build` crate
// processes it further.
fn parse_node_lib_file(node_gyp_output: &str) -> &str {
    let node_lib_file_flag_pattern = "'-Dnode_lib_file=";
    let node_lib_file_start_index = node_gyp_output
        .find(node_lib_file_flag_pattern)
        .map(|i| i + node_lib_file_flag_pattern.len())
        .expect("Couldn't find node_lib_file in node-gyp output.");
    let node_lib_file_end_index = node_gyp_output[node_lib_file_start_index..].find("'").unwrap() + node_lib_file_start_index;
    &node_gyp_output[node_lib_file_start_index..node_lib_file_end_index]
}

fn build_object_file() {
    if cfg!(windows) {
        // Downcase all the npm environment variables to ensure they are read by node-gyp.
        for (key, value) in env::vars() {
            if key.starts_with("NPM_CONFIG") {
                env::remove_var(&key);
                env::set_var(key.to_lowercase(), value);
            }
        }
    }

    // Ensure that all package.json dependencies and dev dependencies are installed.
    npm().args(&["install", "--silent"]).status().ok().expect("Failed to run \"npm install\" for neon-runtime!");

    // Run `node-gyp configure` in verbose mode to read node_root_dir on Windows.
    let output = npm()
        .args(&["run", if debug() { "configure-debug" } else { "configure-release" }])
        .output()
        .expect("Failed to run \"node-gyp configure\" for neon-runtime!");

    if cfg!(windows) {
        let node_gyp_output = String::from_utf8_lossy(&output.stderr);
        println!("cargo:node_arch={}", parse_node_arch(&node_gyp_output));
        println!("cargo:node_root_dir={}", parse_node_root_dir(&node_gyp_output));
        println!("cargo:node_lib_file={}", parse_node_lib_file(&node_gyp_output));
    }

    // Run `node-gyp build`.
    npm()
        .args(&["run", if debug() { "build-debug" } else { "build-release" }])
        .status()
        .ok()
        .expect("Failed to run \"node-gyp build\" for neon-runtime!");
}

// Link the built object file into a static library.
fn link_library() {
    let configuration = if debug() { "Debug" } else { "Release" };
    let object_path = if cfg!(unix) {
        format!("build/{}/obj.target/neon/src/neon.o", configuration)
    } else {
        format!("build\\{}\\obj\\neon\\neon.obj", configuration)
    };

    gcc::Build::new().object(object_path).compile("libneon.a");
}

fn debug() -> bool {
    match env::var("DEBUG") {
        Ok(s) => s == "true",
        Err(_) => false
    }
}
<|endoftext|>


<commit_before>//! `ra_assits` crate provides a bunch of code assists, aslo known as code
//! actions (in LSP) or intentions (in IntelliJ).
//!
//! An assist is a micro-refactoring, which is automatically activated in
//! certain context. For example, if the cursor is over `,`, a "swap `,`" assist
//! becomes available.

mod assist_ctx;

use ra_text_edit::TextEdit;
use ra_syntax::{TextRange, TextUnit, SyntaxNode, Direction};
use ra_db::FileRange;
use hir::db::HirDatabase;

pub(crate) use crate::assist_ctx::{AssistCtx, Assist};

#[derive(Debug)]
pub struct AssistLabel {
    /// Short description of the assist, as shown in the UI.
    pub label: String,
}

pub struct AssistAction {
    pub edit: TextEdit,
    pub cursor_position: Option<TextUnit>,
    pub target: Option<TextRange>,
}

/// Return all the assists applicable at the given position.
///
/// Assists are returned in the "unresolved" state, that is only labels are
/// returned, without actual edits.
pub fn applicable_assists<H>(db: &H, range: FileRange) -> Vec<AssistLabel>
where
    H: HirDatabase + 'static,
{
    AssistCtx::with_ctx(db, range, false, |ctx| {
        all_assists()
            .iter()
            .filter_map(|f| f(ctx.clone()))
            .map(|a| match a {
                Assist::Unresolved(label) => label,
                Assist::Resolved(..) => unreachable!(),
            })
            .collect()
    })
}

/// Return all the assists applicable at the given position.
///
/// Assists are returned in the "resolved" state, that is with edit fully
/// computed.
pub fn assists<H>(db: &H, range: FileRange) -> Vec<(AssistLabel, AssistAction)>
where
    H: HirDatabase + 'static,
{
    use std::cmp::Ordering;

    AssistCtx::with_ctx(db, range, true, |ctx| {
        let mut a = all_assists()
            .iter()
            .filter_map(|f| f(ctx.clone()))
            .map(|a| match a {
                Assist::Resolved(label, action) => (label, action),
                Assist::Unresolved(..) => unreachable!(),
            })
            .collect::<Vec<(AssistLabel, AssistAction)>>();
        a.sort_by(|a, b| match a {
            // Some(y) < Some(x) < None for y < x
            (_, AssistAction { target: Some(a), .. }) => match b {
                (_, AssistAction { target: Some(b), .. }) => a.len().cmp(&b.len()),
                _ => Ordering::Less,
            },
            _ => Ordering::Greater,
        });
        a
    })
}

mod add_derive;
mod add_impl;
mod flip_comma;
mod change_visibility;
mod fill_match_arms;
mod introduce_variable;
mod replace_if_let_with_match;
mod split_import;
mod remove_dbg;
fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] {
    &[
        add_derive::add_derive,
        add_impl::add_impl,
        change_visibility::change_visibility,
        fill_match_arms::fill_match_arms,
        flip_comma::flip_comma,
        introduce_variable::introduce_variable,
        replace_if_let_with_match::replace_if_let_with_match,
        split_import::split_import,
        remove_dbg::remove_dbg,
    ]
}

fn non_trivia_sibling(node: &SyntaxNode, direction: Direction) -> Option<&SyntaxNode> {
    node.siblings(direction).skip(1).find(|node| !node.kind().is_trivia())
}

#[cfg(test)]
mod helpers {
    use hir::mock::MockDatabase;
    use ra_syntax::TextRange;
    use ra_db::FileRange;
    use test_utils::{extract_offset, assert_eq_text, add_cursor, extract_range};

    use crate::{AssistCtx, Assist};

    pub(crate) fn check_assist(
        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
        before: &str,
        after: &str,
    ) {
        let (before_cursor_pos, before) = extract_offset(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange =
            FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
        let assist =
            AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
        let action = match assist {
            Assist::Unresolved(_) => unreachable!(),
            Assist::Resolved(_, it) => it,
        };

        let actual = action.edit.apply(&before);
        let actual_cursor_pos = match action.cursor_position {
            None => action
                .edit
                .apply_to_offset(before_cursor_pos)
                .expect("cursor position is affected by the edit"),
            Some(off) => off,
        };
        let actual = add_cursor(&actual, actual_cursor_pos);
        assert_eq_text!(after, &actual);
    }

    pub(crate) fn check_assist_range(
        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
        before: &str,
        after: &str,
    ) {
        let (range, before) = extract_range(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange = FileRange { file_id, range };
        let assist =
            AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
        let action = match assist {
            Assist::Unresolved(_) => unreachable!(),
            Assist::Resolved(_, it) => it,
        };

        let mut actual = action.edit.apply(&before);
        if let Some(pos) = action.cursor_position {
            actual = add_cursor(&actual, pos);
        }
        assert_eq_text!(after, &actual);
    }

    pub(crate) fn check_assist_target(
        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
        before: &str,
        target: &str,
    ) {
        let (before_cursor_pos, before) = extract_offset(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange =
            FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
        let assist =
            AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
        let action = match assist {
            Assist::Unresolved(_) => unreachable!(),
            Assist::Resolved(_, it) => it,
        };

        let range = action.target.expect("expected target on action");
        assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
    }

    pub(crate) fn check_assist_range_target(
        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
        before: &str,
        target: &str,
    ) {
        let (range, before) = extract_range(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange = FileRange { file_id, range };
        let assist =
            AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
        let action = match assist {
            Assist::Unresolved(_) => unreachable!(),
            Assist::Resolved(_, it) => it,
        };

        let range = action.target.expect("expected target on action");
        assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
    }

    pub(crate) fn check_assist_not_applicable(
        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
        before: &str,
    ) {
        let (before_cursor_pos, before) = extract_offset(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange =
            FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
        let assist = AssistCtx::with_ctx(&db, frange, true, assist);
        assert!(assist.is_none());
    }
}

#[cfg(test)]
mod tests {
    use hir::mock::MockDatabase;
    use ra_syntax::TextRange;
    use ra_db::FileRange;
    use test_utils::{extract_offset, extract_range};

    #[test]
    fn assist_order_field_struct() {
        let before = "struct Foo { <|>bar: u32 }";
        let (before_cursor_pos, before) = extract_offset(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange =
            FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
        let assists = super::assists(&db, frange);
        let mut assists = assists.iter();

        assert_eq!(assists.next().expect("expected assist").0.label, "make pub(crate)");
        assert_eq!(assists.next().expect("expected assist").0.label, "add `#[derive]`");
    }

    #[test]
    fn assist_order_if_expr() {
        let before = "
        pub fn test_some_range(a: int) -> bool {
            if let 2..6 = 5<|> {
                true
            } else {
                false
            }
        }";
        let (before_cursor_pos, before) = extract_offset(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange =
            FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
        let assists = super::assists(&db, frange);
        let mut assists = assists.iter();

        assert_eq!(assists.next().expect("expected assist").0.label, "introduce variable");
        assert_eq!(assists.next().expect("expected assist").0.label, "replace with match");
    }

}
<commit_msg>Remove unused import<commit_after>//! `ra_assits` crate provides a bunch of code assists, aslo known as code
//! actions (in LSP) or intentions (in IntelliJ).
//!
//! An assist is a micro-refactoring, which is automatically activated in
//! certain context. For example, if the cursor is over `,`, a "swap `,`" assist
//! becomes available.

mod assist_ctx;

use ra_text_edit::TextEdit;
use ra_syntax::{TextRange, TextUnit, SyntaxNode, Direction};
use ra_db::FileRange;
use hir::db::HirDatabase;

pub(crate) use crate::assist_ctx::{AssistCtx, Assist};

#[derive(Debug)]
pub struct AssistLabel {
    /// Short description of the assist, as shown in the UI.
    pub label: String,
}

pub struct AssistAction {
    pub edit: TextEdit,
    pub cursor_position: Option<TextUnit>,
    pub target: Option<TextRange>,
}

/// Return all the assists applicable at the given position.
///
/// Assists are returned in the "unresolved" state, that is only labels are
/// returned, without actual edits.
pub fn applicable_assists<H>(db: &H, range: FileRange) -> Vec<AssistLabel>
where
    H: HirDatabase + 'static,
{
    AssistCtx::with_ctx(db, range, false, |ctx| {
        all_assists()
            .iter()
            .filter_map(|f| f(ctx.clone()))
            .map(|a| match a {
                Assist::Unresolved(label) => label,
                Assist::Resolved(..) => unreachable!(),
            })
            .collect()
    })
}

/// Return all the assists applicable at the given position.
///
/// Assists are returned in the "resolved" state, that is with edit fully
/// computed.
pub fn assists<H>(db: &H, range: FileRange) -> Vec<(AssistLabel, AssistAction)>
where
    H: HirDatabase + 'static,
{
    use std::cmp::Ordering;

    AssistCtx::with_ctx(db, range, true, |ctx| {
        let mut a = all_assists()
            .iter()
            .filter_map(|f| f(ctx.clone()))
            .map(|a| match a {
                Assist::Resolved(label, action) => (label, action),
                Assist::Unresolved(..) => unreachable!(),
            })
            .collect::<Vec<(AssistLabel, AssistAction)>>();
        a.sort_by(|a, b| match a {
            // Some(y) < Some(x) < None for y < x
            (_, AssistAction { target: Some(a), .. }) => match b {
                (_, AssistAction { target: Some(b), .. }) => a.len().cmp(&b.len()),
                _ => Ordering::Less,
            },
            _ => Ordering::Greater,
        });
        a
    })
}

mod add_derive;
mod add_impl;
mod flip_comma;
mod change_visibility;
mod fill_match_arms;
mod introduce_variable;
mod replace_if_let_with_match;
mod split_import;
mod remove_dbg;
fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] {
    &[
        add_derive::add_derive,
        add_impl::add_impl,
        change_visibility::change_visibility,
        fill_match_arms::fill_match_arms,
        flip_comma::flip_comma,
        introduce_variable::introduce_variable,
        replace_if_let_with_match::replace_if_let_with_match,
        split_import::split_import,
        remove_dbg::remove_dbg,
    ]
}

fn non_trivia_sibling(node: &SyntaxNode, direction: Direction) -> Option<&SyntaxNode> {
    node.siblings(direction).skip(1).find(|node| !node.kind().is_trivia())
}

#[cfg(test)]
mod helpers {
    use hir::mock::MockDatabase;
    use ra_syntax::TextRange;
    use ra_db::FileRange;
    use test_utils::{extract_offset, extract_range, assert_eq_text, add_cursor};

    use crate::{AssistCtx, Assist};

    pub(crate) fn check_assist(
        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
        before: &str,
        after: &str,
    ) {
        let (before_cursor_pos, before) = extract_offset(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange =
            FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
        let assist =
            AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
        let action = match assist {
            Assist::Unresolved(_) => unreachable!(),
            Assist::Resolved(_, it) => it,
        };

        let actual = action.edit.apply(&before);
        let actual_cursor_pos = match action.cursor_position {
            None => action
                .edit
                .apply_to_offset(before_cursor_pos)
                .expect("cursor position is affected by the edit"),
            Some(off) => off,
        };
        let actual = add_cursor(&actual, actual_cursor_pos);
        assert_eq_text!(after, &actual);
    }

    pub(crate) fn check_assist_range(
        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
        before: &str,
        after: &str,
    ) {
        let (range, before) = extract_range(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange = FileRange { file_id, range };
        let assist =
            AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
        let action = match assist {
            Assist::Unresolved(_) => unreachable!(),
            Assist::Resolved(_, it) => it,
        };

        let mut actual = action.edit.apply(&before);
        if let Some(pos) = action.cursor_position {
            actual = add_cursor(&actual, pos);
        }
        assert_eq_text!(after, &actual);
    }

    pub(crate) fn check_assist_target(
        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
        before: &str,
        target: &str,
    ) {
        let (before_cursor_pos, before) = extract_offset(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange =
            FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
        let assist =
            AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
        let action = match assist {
            Assist::Unresolved(_) => unreachable!(),
            Assist::Resolved(_, it) => it,
        };

        let range = action.target.expect("expected target on action");
        assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
    }

    pub(crate) fn check_assist_range_target(
        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
        before: &str,
        target: &str,
    ) {
        let (range, before) = extract_range(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange = FileRange { file_id, range };
        let assist =
            AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
        let action = match assist {
            Assist::Unresolved(_) => unreachable!(),
            Assist::Resolved(_, it) => it,
        };

        let range = action.target.expect("expected target on action");
        assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
    }

    pub(crate) fn check_assist_not_applicable(
        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
        before: &str,
    ) {
        let (before_cursor_pos, before) = extract_offset(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange =
            FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
        let assist = AssistCtx::with_ctx(&db, frange, true, assist);
        assert!(assist.is_none());
    }
}

#[cfg(test)]
mod tests {
    use hir::mock::MockDatabase;
    use ra_syntax::TextRange;
    use ra_db::FileRange;
    use test_utils::{extract_offset};

    #[test]
    fn assist_order_field_struct() {
        let before = "struct Foo { <|>bar: u32 }";
        let (before_cursor_pos, before) = extract_offset(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange =
            FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
        let assists = super::assists(&db, frange);
        let mut assists = assists.iter();

        assert_eq!(assists.next().expect("expected assist").0.label, "make pub(crate)");
        assert_eq!(assists.next().expect("expected assist").0.label, "add `#[derive]`");
    }

    #[test]
    fn assist_order_if_expr() {
        let before = "
        pub fn test_some_range(a: int) -> bool {
            if let 2..6 = 5<|> {
                true
            } else {
                false
            }
        }";
        let (before_cursor_pos, before) = extract_offset(before);
        let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
        let frange =
            FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
        let assists = super::assists(&db, frange);
        let mut assists = assists.iter();

        assert_eq!(assists.next().expect("expected assist").0.label, "introduce variable");
        assert_eq!(assists.next().expect("expected assist").0.label, "replace with match");
    }

}
<|endoftext|>


<commit_before>//! `NameDefinition` keeps information about the element we want to search references for.
//! The element is represented by `NameKind`. It's located inside some `container` and
//! has a `visibility`, which defines a search scope.
//! Note that the reference search is possible for not all of the classified items.

// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).

use hir::{
    Adt, Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, Name, PathResolution,
    Semantics, TypeParam, Visibility,
};
use ra_prof::profile;
use ra_syntax::{
    ast::{self, AstNode},
    match_ast,
};
use test_utils::tested_by;

use crate::RootDatabase;

// FIXME: a more precise name would probably be `Symbol`?
#[derive(Debug, PartialEq, Eq)]
pub enum Definition {
    Macro(MacroDef),
    Field(Field),
    ModuleDef(ModuleDef),
    SelfType(ImplDef),
    Local(Local),
    TypeParam(TypeParam),
}

impl Definition {
    pub fn module(&self, db: &RootDatabase) -> Option<Module> {
        match self {
            Definition::Macro(it) => it.module(db),
            Definition::Field(it) => Some(it.parent_def(db).module(db)),
            Definition::ModuleDef(it) => it.module(db),
            Definition::SelfType(it) => Some(it.module(db)),
            Definition::Local(it) => Some(it.module(db)),
            Definition::TypeParam(it) => Some(it.module(db)),
        }
    }

    pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> {
        let module = self.module(db);

        match self {
            Definition::Macro(_) => None,
            Definition::Field(sf) => Some(sf.visibility(db)),
            Definition::ModuleDef(def) => match def {
                ModuleDef::EnumVariant(id) => {
                    let parent = id.parent_enum(db);
                    module?.visibility_of(db, &ModuleDef::Adt(Adt::Enum(parent)))
                }
                ModuleDef::Function(f) => Some(f.visibility(db)),
                _ => module?.visibility_of(db, def),
            },
            Definition::SelfType(_) => None,
            Definition::Local(_) => None,
            Definition::TypeParam(_) => None,
        }
    }

    pub fn name(&self, db: &RootDatabase) -> Option<Name> {
        let name = match self {
            Definition::Macro(it) => it.name(db)?,
            Definition::Field(it) => it.name(db),
            Definition::ModuleDef(def) => match def {
                hir::ModuleDef::Module(it) => it.name(db)?,
                hir::ModuleDef::Function(it) => it.name(db),
                hir::ModuleDef::Adt(def) => match def {
                    hir::Adt::Struct(it) => it.name(db),
                    hir::Adt::Union(it) => it.name(db),
                    hir::Adt::Enum(it) => it.name(db),
                },
                hir::ModuleDef::EnumVariant(it) => it.name(db),
                hir::ModuleDef::Const(it) => it.name(db)?,
                hir::ModuleDef::Static(it) => it.name(db)?,
                hir::ModuleDef::Trait(it) => it.name(db),
                hir::ModuleDef::TypeAlias(it) => it.name(db),
                hir::ModuleDef::BuiltinType(_) => return None,
            },
            Definition::SelfType(_) => return None,
            Definition::Local(it) => it.name(db)?,
            Definition::TypeParam(it) => it.name(db),
        };
        Some(name)
    }
}

pub enum NameClass {
    Definition(Definition),
    /// `None` in `if let None = Some(82) {}`
    ConstReference(Definition),
}

impl NameClass {
    pub fn into_definition(self) -> Option<Definition> {
        match self {
            NameClass::Definition(it) => Some(it),
            NameClass::ConstReference(_) => None,
        }
    }

    pub fn definition(self) -> Definition {
        match self {
            NameClass::Definition(it) | NameClass::ConstReference(it) => it,
        }
    }
}

pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
    let _p = profile("classify_name");

    if let Some(bind_pat) = name.syntax().parent().and_then(ast::BindPat::cast) {
        if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) {
            return Some(NameClass::ConstReference(Definition::ModuleDef(def)));
        }
    }

    classify_name_inner(sema, name).map(NameClass::Definition)
}

fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<Definition> {
    let parent = name.syntax().parent()?;

    match_ast! {
        match parent {
            ast::Alias(it) => {
                tested_by!(goto_def_for_use_alias; force);
                let use_tree = it.syntax().parent().and_then(ast::UseTree::cast)?;
                let path = use_tree.path()?;
                let path_segment = path.segment()?;
                let name_ref = path_segment.name_ref()?;
                let name_ref_class = classify_name_ref(sema, &name_ref)?;

                Some(name_ref_class.definition())
            },
            ast::BindPat(it) => {
                let local = sema.to_def(&it)?;
                Some(Definition::Local(local))
            },
            ast::RecordFieldDef(it) => {
                let field: hir::Field = sema.to_def(&it)?;
                Some(Definition::Field(field))
            },
            ast::Module(it) => {
                let def = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::StructDef(it) => {
                let def: hir::Struct = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::UnionDef(it) => {
                let def: hir::Union = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::EnumDef(it) => {
                let def: hir::Enum = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::TraitDef(it) => {
                let def: hir::Trait = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::StaticDef(it) => {
                let def: hir::Static = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::EnumVariant(it) => {
                let def: hir::EnumVariant = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::FnDef(it) => {
                let def: hir::Function = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::ConstDef(it) => {
                let def: hir::Const = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::TypeAliasDef(it) => {
                let def: hir::TypeAlias = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::MacroCall(it) => {
                let def = sema.to_def(&it)?;
                Some(Definition::Macro(def))
            },
            ast::TypeParam(it) => {
                let def = sema.to_def(&it)?;
                Some(Definition::TypeParam(def))
            },
            _ => None,
        }
    }
}

#[derive(Debug)]
pub enum NameRefClass {
    Definition(Definition),
    FieldShorthand { local: Local, field: Definition },
}

impl NameRefClass {
    pub fn definition(self) -> Definition {
        match self {
            NameRefClass::Definition(def) => def,
            NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local),
        }
    }
}

pub fn classify_name_ref(
    sema: &Semantics<RootDatabase>,
    name_ref: &ast::NameRef,
) -> Option<NameRefClass> {
    let _p = profile("classify_name_ref");

    let parent = name_ref.syntax().parent()?;

    if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
        tested_by!(goto_def_for_methods; force);
        if let Some(func) = sema.resolve_method_call(&method_call) {
            return Some(NameRefClass::Definition(Definition::ModuleDef(func.into())));
        }
    }

    if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
        tested_by!(goto_def_for_fields; force);
        if let Some(field) = sema.resolve_field(&field_expr) {
            return Some(NameRefClass::Definition(Definition::Field(field)));
        }
    }

    if let Some(record_field) = ast::RecordField::for_field_name(name_ref) {
        tested_by!(goto_def_for_record_fields; force);
        tested_by!(goto_def_for_field_init_shorthand; force);
        if let Some((field, local)) = sema.resolve_record_field(&record_field) {
            let field = Definition::Field(field);
            let res = match local {
                None => NameRefClass::Definition(field),
                Some(local) => NameRefClass::FieldShorthand { field, local },
            };
            return Some(res);
        }
    }

    if let Some(record_field_pat) = ast::RecordFieldPat::cast(parent.clone()) {
        tested_by!(goto_def_for_record_field_pats; force);
        if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) {
            let field = Definition::Field(field);
            return Some(NameRefClass::Definition(field));
        }
    }

    if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
        tested_by!(goto_def_for_macros; force);
        if let Some(macro_def) = sema.resolve_macro_call(&macro_call) {
            return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
        }
    }

    let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
    let resolved = sema.resolve_path(&path)?;
    let res = match resolved {
        PathResolution::Def(def) => Definition::ModuleDef(def),
        PathResolution::AssocItem(item) => {
            let def = match item {
                hir::AssocItem::Function(it) => it.into(),
                hir::AssocItem::Const(it) => it.into(),
                hir::AssocItem::TypeAlias(it) => it.into(),
            };
            Definition::ModuleDef(def)
        }
        PathResolution::Local(local) => Definition::Local(local),
        PathResolution::TypeParam(par) => Definition::TypeParam(par),
        PathResolution::Macro(def) => Definition::Macro(def),
        PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
    };
    Some(NameRefClass::Definition(res))
}
<commit_msg>Also for consts and type aliases<commit_after>//! `NameDefinition` keeps information about the element we want to search references for.
//! The element is represented by `NameKind`. It's located inside some `container` and
//! has a `visibility`, which defines a search scope.
//! Note that the reference search is possible for not all of the classified items.

// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).

use hir::{
    Adt, Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, Name, PathResolution,
    Semantics, TypeParam, Visibility,
};
use ra_prof::profile;
use ra_syntax::{
    ast::{self, AstNode},
    match_ast,
};
use test_utils::tested_by;

use crate::RootDatabase;

// FIXME: a more precise name would probably be `Symbol`?
#[derive(Debug, PartialEq, Eq)]
pub enum Definition {
    Macro(MacroDef),
    Field(Field),
    ModuleDef(ModuleDef),
    SelfType(ImplDef),
    Local(Local),
    TypeParam(TypeParam),
}

impl Definition {
    pub fn module(&self, db: &RootDatabase) -> Option<Module> {
        match self {
            Definition::Macro(it) => it.module(db),
            Definition::Field(it) => Some(it.parent_def(db).module(db)),
            Definition::ModuleDef(it) => it.module(db),
            Definition::SelfType(it) => Some(it.module(db)),
            Definition::Local(it) => Some(it.module(db)),
            Definition::TypeParam(it) => Some(it.module(db)),
        }
    }

    pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> {
        let module = self.module(db);

        match self {
            Definition::Macro(_) => None,
            Definition::Field(sf) => Some(sf.visibility(db)),
            Definition::ModuleDef(def) => match def {
                ModuleDef::EnumVariant(id) => {
                    let parent = id.parent_enum(db);
                    module?.visibility_of(db, &ModuleDef::Adt(Adt::Enum(parent)))
                }
                ModuleDef::Function(f) => Some(f.visibility(db)),
                ModuleDef::Const(c) => Some(c.visibility(db)),
                ModuleDef::TypeAlias(t) => Some(t.visibility(db)),
                _ => module?.visibility_of(db, def),
            },
            Definition::SelfType(_) => None,
            Definition::Local(_) => None,
            Definition::TypeParam(_) => None,
        }
    }

    pub fn name(&self, db: &RootDatabase) -> Option<Name> {
        let name = match self {
            Definition::Macro(it) => it.name(db)?,
            Definition::Field(it) => it.name(db),
            Definition::ModuleDef(def) => match def {
                hir::ModuleDef::Module(it) => it.name(db)?,
                hir::ModuleDef::Function(it) => it.name(db),
                hir::ModuleDef::Adt(def) => match def {
                    hir::Adt::Struct(it) => it.name(db),
                    hir::Adt::Union(it) => it.name(db),
                    hir::Adt::Enum(it) => it.name(db),
                },
                hir::ModuleDef::EnumVariant(it) => it.name(db),
                hir::ModuleDef::Const(it) => it.name(db)?,
                hir::ModuleDef::Static(it) => it.name(db)?,
                hir::ModuleDef::Trait(it) => it.name(db),
                hir::ModuleDef::TypeAlias(it) => it.name(db),
                hir::ModuleDef::BuiltinType(_) => return None,
            },
            Definition::SelfType(_) => return None,
            Definition::Local(it) => it.name(db)?,
            Definition::TypeParam(it) => it.name(db),
        };
        Some(name)
    }
}

pub enum NameClass {
    Definition(Definition),
    /// `None` in `if let None = Some(82) {}`
    ConstReference(Definition),
}

impl NameClass {
    pub fn into_definition(self) -> Option<Definition> {
        match self {
            NameClass::Definition(it) => Some(it),
            NameClass::ConstReference(_) => None,
        }
    }

    pub fn definition(self) -> Definition {
        match self {
            NameClass::Definition(it) | NameClass::ConstReference(it) => it,
        }
    }
}

pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
    let _p = profile("classify_name");

    if let Some(bind_pat) = name.syntax().parent().and_then(ast::BindPat::cast) {
        if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) {
            return Some(NameClass::ConstReference(Definition::ModuleDef(def)));
        }
    }

    classify_name_inner(sema, name).map(NameClass::Definition)
}

fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<Definition> {
    let parent = name.syntax().parent()?;

    match_ast! {
        match parent {
            ast::Alias(it) => {
                tested_by!(goto_def_for_use_alias; force);
                let use_tree = it.syntax().parent().and_then(ast::UseTree::cast)?;
                let path = use_tree.path()?;
                let path_segment = path.segment()?;
                let name_ref = path_segment.name_ref()?;
                let name_ref_class = classify_name_ref(sema, &name_ref)?;

                Some(name_ref_class.definition())
            },
            ast::BindPat(it) => {
                let local = sema.to_def(&it)?;
                Some(Definition::Local(local))
            },
            ast::RecordFieldDef(it) => {
                let field: hir::Field = sema.to_def(&it)?;
                Some(Definition::Field(field))
            },
            ast::Module(it) => {
                let def = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::StructDef(it) => {
                let def: hir::Struct = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::UnionDef(it) => {
                let def: hir::Union = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::EnumDef(it) => {
                let def: hir::Enum = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::TraitDef(it) => {
                let def: hir::Trait = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::StaticDef(it) => {
                let def: hir::Static = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::EnumVariant(it) => {
                let def: hir::EnumVariant = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::FnDef(it) => {
                let def: hir::Function = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::ConstDef(it) => {
                let def: hir::Const = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::TypeAliasDef(it) => {
                let def: hir::TypeAlias = sema.to_def(&it)?;
                Some(Definition::ModuleDef(def.into()))
            },
            ast::MacroCall(it) => {
                let def = sema.to_def(&it)?;
                Some(Definition::Macro(def))
            },
            ast::TypeParam(it) => {
                let def = sema.to_def(&it)?;
                Some(Definition::TypeParam(def))
            },
            _ => None,
        }
    }
}

#[derive(Debug)]
pub enum NameRefClass {
    Definition(Definition),
    FieldShorthand { local: Local, field: Definition },
}

impl NameRefClass {
    pub fn definition(self) -> Definition {
        match self {
            NameRefClass::Definition(def) => def,
            NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local),
        }
    }
}

pub fn classify_name_ref(
    sema: &Semantics<RootDatabase>,
    name_ref: &ast::NameRef,
) -> Option<NameRefClass> {
    let _p = profile("classify_name_ref");

    let parent = name_ref.syntax().parent()?;

    if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
        tested_by!(goto_def_for_methods; force);
        if let Some(func) = sema.resolve_method_call(&method_call) {
            return Some(NameRefClass::Definition(Definition::ModuleDef(func.into())));
        }
    }

    if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
        tested_by!(goto_def_for_fields; force);
        if let Some(field) = sema.resolve_field(&field_expr) {
            return Some(NameRefClass::Definition(Definition::Field(field)));
        }
    }

    if let Some(record_field) = ast::RecordField::for_field_name(name_ref) {
        tested_by!(goto_def_for_record_fields; force);
        tested_by!(goto_def_for_field_init_shorthand; force);
        if let Some((field, local)) = sema.resolve_record_field(&record_field) {
            let field = Definition::Field(field);
            let res = match local {
                None => NameRefClass::Definition(field),
                Some(local) => NameRefClass::FieldShorthand { field, local },
            };
            return Some(res);
        }
    }

    if let Some(record_field_pat) = ast::RecordFieldPat::cast(parent.clone()) {
        tested_by!(goto_def_for_record_field_pats; force);
        if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) {
            let field = Definition::Field(field);
            return Some(NameRefClass::Definition(field));
        }
    }

    if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
        tested_by!(goto_def_for_macros; force);
        if let Some(macro_def) = sema.resolve_macro_call(&macro_call) {
            return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
        }
    }

    let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
    let resolved = sema.resolve_path(&path)?;
    let res = match resolved {
        PathResolution::Def(def) => Definition::ModuleDef(def),
        PathResolution::AssocItem(item) => {
            let def = match item {
                hir::AssocItem::Function(it) => it.into(),
                hir::AssocItem::Const(it) => it.into(),
                hir::AssocItem::TypeAlias(it) => it.into(),
            };
            Definition::ModuleDef(def)
        }
        PathResolution::Local(local) => Definition::Local(local),
        PathResolution::TypeParam(par) => Definition::TypeParam(par),
        PathResolution::Macro(def) => Definition::Macro(def),
        PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
    };
    Some(NameRefClass::Definition(res))
}
<|endoftext|>