module loader.loader;

version(Windows)
	import loader.windows;
else version(Posix)
	import loader.posix;
else
	static assert(false, "unsupported platform");

import std.exception;
import std.string;

class DynamicLoaderException : Exception
{
	this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
	{
		super(msg, file, line, next);
	}
}

struct DynamicLibrary
{
	private:
	string libraryName;
	void* handle;

	public:
	this(in char[] name)
	{
		auto zName = toStringz(name);

		libraryName = zName[0 .. name.length];

		handle = loadLibrary(zName);

		enforce(handle, new DynamicLoaderException(format(`failed to load library: %s`, libraryError())));
	}

	void resolve(alias funcPtr)(string file = __FILE__, size_t line = __LINE__)
	{
		static if(__traits(identifier, funcPtr).length >= 2 &&
			__traits(identifier, funcPtr)[$ -2 .. $] == "_p")
			enum name = __traits(identifier, funcPtr)[0 .. $ - 2];
		else
			enum name = __traits(identifier, funcPtr);

		funcPtr = cast(typeof(funcPtr))loadSymbol(handle, name);

		enforce(funcPtr, new DynamicLoaderException(
			format(`unable to find symbol "%s" in library "%s"`, name, libraryName),
			file, line));
	}
}