module std.format;

import dlib.util;
import std.traits;
import wasm;

char[]
sformat(Char, Args...)(scope return char[] buf, scope const(Char)[] fmt, Args args) @nogc
{
	SprintfType type = SprintfType.None;
	static foreach(i; 0 .. Args.length)
	{
		static if(isArray!(Args[i]) || is(Args[i] == string))
		{
			{
				alias ElementType = typeof(*Args[i].init.ptr);

				with(SprintfType)
				{
					static      if(is(Args[i]     == string)) type = String;
					else static if(is(ElementType == ubyte))  type = U8Array;
					else static if(is(ElementType == byte))   type = I8Array;
					else static if(is(ElementType == ushort)) type = U16Array;
					else static if(is(ElementType == short))  type = I16Array;
					else static if(is(ElementType == uint))   type = U32Array;
					else static if(is(ElementType == int))    type = I32Array;
					else static if(is(ElementType == ulong))  type = U64Array;
					else static if(is(ElementType == long))   type = I64Array;
					else static if(is(ElementType == float))  type = F32Array;
					else static if(is(ElementType == double)) type = F64Array;
					else static if(is(ElementType == char))   type = CharArray;
					else static assert(false, "Type unsupported");
				}

				SprintfLoadArray(args[i].length, args[i].ptr, type);
			}
		}
		else
		{
			with(SprintfType)
			{
				static      if(is(Args[i] == ubyte))  type = U8;
				else static if(is(Args[i] == byte))   type = I8;
				else static if(is(Args[i] == ushort)) type = U16;
				else static if(is(Args[i] == short))  type = I16;
				else static if(is(Args[i] == uint))   type = U32;
				else static if(is(Args[i] == int))    type = I32;
				else static if(is(Args[i] == ulong))  type = U64;
				else static if(is(Args[i] == long))   type = I64;
				else static if(is(Args[i] == size_t)) type = SizeT;
				else static if(is(Args[i] == float))  type = F32;
				else static if(is(Args[i] == double)) type = F64;
				else static if(is(Args[i] == bool))   type = Bool;
				else static if(is(Args[i] == char))   type = Char;
				else static if(isPointer!(Args[i]))   type = Pointer;
				else static assert(false, "Type unsupported");
			}

			static if(isPointer!(Args[i]))
			{
				SprintfLoadValue(args[i], type);
			}
			else
			{
				SprintfLoadValue(&args[i], type);
			}
		}
	}

	size_t length = SprintfEnd(buf, Str(fmt));

	return buf[0 .. length];
}

char[]
sformat(alias fmt, Args...)(char[] buf, Args args) @nogc if(isSomeString!(typeof(fmt)))
{
	return .sformat(buf, fmt, args);
}

