view dstep/internal/Reflection.d @ 26:6825fcc47e39

Added dstep.internal.Reflection
author Jacob Carlborg <doob@me.com>
date Tue, 06 Apr 2010 11:38:08 +0200
parents
children
line wrap: on
line source

/**
 * Copyright: Copyright (c) 2010 Jacob Carlborg.
 * Authors: Jacob Carlborg
 * Version: Initial created: Mar 8, 2010
 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
 */
module dstep.internal.Reflection;

import dstep.objc.bridge.Bridge;
import dstep.internal.String;

/**
 * Returns the name of the given function
 * 
 * Params:
 *     func = the function alias to get the name of
 *     
 * Returns: the name of the function 
 */
template functionNameOf (alias func)
{
	version(LDC)
		const functionNameOf = (&func).stringof[1 .. $];
	
	else
		const functionNameOf = (&func).stringof[2 .. $];
}

/**
 * Returns the parameter names of the given function
 * 
 * Params:
 *     func = the function alias to get the parameter names of
 *     
 * Returns: an array of strings containing the parameter names 
 */
template parameterNamesOf (alias func)
{
	const parameterNamesOf = parameterNamesOfImpl!(func);
}

private string[] parameterNamesOfImpl (alias func) ()
{
	string funcStr = typeof(&func).stringof;

	auto start = funcStr.indexOf('(');
	auto end = funcStr.indexOf(')');
	
	const firstPattern = ' ';
	const secondPattern = ',';
	
	funcStr = funcStr[start + 1 .. end];
	
	if (funcStr == "")
		return null;
		
	funcStr ~= secondPattern;
	
	string token;
	string[] arr;
	
	foreach (c ; funcStr)
	{		
		if (c != firstPattern && c != secondPattern)
			token ~= c;
		
		else
		{			
			if (token)
				arr ~= token;
			
			token = null;
		}			
	}
	
	if (arr.length == 1)
		return arr;
	
	string[] result;
	bool skip = false;
	
	foreach (str ; arr)
	{
		skip = !skip;
		
		if (skip)
			continue;
		
		result ~= str;
	}
	
	return result;
}

/**
 * Compile-time function to get the index of the give element.
 * 
 * Performs a linear scan, returning the index of the first occurrence 
 * of the specified element in the array, or U.max if the array does 
 * not contain the element.
 * 
 * Params:
 *     arr = the array to get the index of the element from
 *     element = the element to find
 *     
 * Returns: the index of the element or size_t.max if the element was not found.
 */
private size_t indexOf (T) (T[] arr, T element)
{
	foreach (i, e ; arr)
		if (e == element)
			return i;
	
	return size_t.max;
}

//FIXME fix this when http://d.puremagic.com/issues/show_bug.cgi?id=3512 is fixed
version (none)
{

/**
 * Compile-time function to get the index of the give element.
 * 
 * Performs a linear scan, returning the index of the first occurrence 
 * of the specified element in the array, or U.max if the array does 
 * not contain the element.
 * 
 * Params:
 *     arr = the array to get the index of the element from
 *     element = the element to find
 *     
 * Returns: the index of the element or size_t.max if the element was not found.
 */
private size_t indexOf (T) (T[] arr, dchar element)
{
	static assert(is(T == char) || is(T == wchar) || is(T == dchar), `dstep.internal.Traits.indexOf: The given type "` ~ T.stringof ~ `" is not valid, it has to be char, wchar or dchar`);
	
	foreach (i, dchar e ; arr)
		if (e == element)
			return i;
	
	return size_t.max;
}
}

/**
 * Evaluates to true if $(D_PARAM T) has a instance method with the given name
 * 
 * Params:
 * 		T = the type of the class/struct
 * 		method = the name of the method
 */
template hasInstanceMethod (T, string method)
{
	const hasInstanceMethod = is(typeof({
		T t;
		mixin("auto f = &t." ~ method ~ ";");
	}));
}

/**
 * Evaluates to true if $(D_PARAM T) has a class method with the given name
 * 
 * Params:
 * 		T = the type of the class/struct
 * 		method = the name of the method
 */
template hasClassMethod (T, string method)
{
	const hasClassMethod = is(typeof({
		mixin("auto f = &T." ~ method ~ ";");
	}));
}

/**
 * Evaluates to true if $(D_PARAM T) has a either a class method or a instance method
 * with the given name.
 * 
 * Params:
 * 		T = the type of the class/struct
 * 		method = the name of the method
 */
template hasMethod (T, string method)
{
	const hasMethod = hasClassMethod!(T, method) || hasInstanceMethod!(T, method);
}

/**
 * Evaluates to true if T has a field with the given name
 * 
 * Params:
 * 		T = the type of the class/struct
 * 		field = the name of the field
 */
template hasField (T, string field)
{
	const hasField = hasFieldImpl!(T, field, 0);
}

private template hasFieldImpl (T, string field, size_t i)
{
	static if (T.tupleof.length == i)
		const hasFieldImpl = false;
	
	else static if (T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] == field)
		const hasFieldImpl = true;
	
	else
		const hasFieldImpl = hasFieldImpl!(T, field, i + 1);		
}

/// Evaluates to true if $(D_PARAM T) has binded methods
template hasBindedMethods (T)
{
	const bool hasBindedMethods = hasField!(T, Bridge.objcClassMethodDeclarationVar) || hasField!(T, Bridge.objcMethodDeclarationVar);
}



/**
 * Sets the given value to the filed with the given name
 * 
 * Params:
 *     t = an instance of the type that has the field
 *     value = the value to set
 */
void setValueOfField (string field, T, U) (ref T t, U value)
in
{
	static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
}
body
{
	const len = T.stringof.length; 
	
	foreach (i, dummy ; typeof(T.tupleof))
	{
		const f = T.tupleof[i].stringof[1 + len + 2 .. $];
		
		static if (f == field)
		{
			t.tupleof[i] = value;
			break;
		}
	}
}

/**
 * Evaluates to the type of the field with the given name
 * 
 * Params:
 * 		T = the type of the class/struct
 * 		field = the name of the field
 */
template TypeOfField (T, string field)
{
	static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");

	alias TypeOfFieldImpl!(T, field, 0) TypeOfField;
}

private template TypeOfFieldImpl (T, string field, size_t i)
{
	static if (T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] == field)
		alias typeof(T.tupleof[i]) TypeOfFieldImpl;
	
	else
		alias TypeOfFieldImpl!(T, field, i + 1) TypeOfFieldImpl;
}

/**
 * Creates a new instance of class with the given name
 * 
 * Params:
 *     name = the fully qualified name of the class
 *     args = the arguments to the constructor
 *     
 * Returns: the newly created instance or null
 */
T factory (T : Object, ARGS...) (string name, ARGS args)
{	
	auto classInfo = ClassInfo.find(name);
	
	if (!classInfo)
		return null;
	
	auto object = newInstance(classInfo);
	
	if (classInfo.flags & 8 && classInfo.defaultConstructor is null)
	{
		auto o = cast(T) object;
		
		static if (is(typeof(o._ctor(args))))
			return o._ctor(args);
		
		else
			return null;
	}
	
	else
	{
		if (classInfo.flags & 8 && classInfo.defaultConstructor !is null)
		{
			Object delegate () ctor;
			ctor.ptr = cast(void*) object;
			ctor.funcptr = cast(Object function()) classInfo.defaultConstructor;
			
			return cast(T) ctor();
		}
		
		else
			return cast(T) object;
	}
}

private
{
	version (LDC)
		extern (C) Object _d_allocclass(ClassInfo);
	
	else
		extern (C) Object _d_newclass(ClassInfo);
}

/**
 * Creates a new instance of the given ClassInfo
 * 
 * Params:
 *     classInfo = the class to create a new instance of
 *     
 * Returns: the new instance
 */
Object newInstance (ClassInfo classInfo)
{
	version (LDC)
	{		
		Object object = _d_allocclass(classInfo);
        (cast(byte*) object)[0 .. classInfo.init.length] = classInfo.init[];
        
        return object;
	}

	else
		return _d_newclass(classInfo);
}