1 module xmlrpcc.data;
2 
3 import std.variant : Variant;
4 import std.algorithm : reduce;
5 import std.conv : to;
6 import std.string : format;
7 
8 import xmlrpcc.error;
9 
10 alias XmlRpcArray = Variant[];
11 alias XmlRpcStruct = Variant[string];
12 
13 @trusted:
14 
15 struct MethodCallData {
16    string name;
17    Variant[] params;
18 
19    string toString() {
20       return name ~ "(" ~ prettyParams(params) ~ ")";
21    }
22 }
23 
24 struct MethodResponseData {
25    bool fault;
26    Variant[] params;
27 
28    string toString() {
29       return (fault ? "FAULT" : "OK") ~ ": " ~ prettyParams(params);
30    }
31 }
32 
33 package string prettyParams(Variant[] params) {
34    return reduce!((a, b) { return a ~ (a.length ? ", " : "") ~ prettyParam(b); })("", params);
35 }
36 
37 private string prettyParam(Variant param) {
38    if (param.convertsTo!string() || param.convertsTo!wstring() || param.convertsTo!dstring())
39       return "`" ~ to!string(param) ~ "`";
40 
41    if (param.convertsTo!(const(ubyte[])))
42       return reduce!((a, b) { return format("%s %02x", a, b); })("hex:", param.get!(const(ubyte[]))());
43 
44    if (param.convertsTo!XmlRpcArray)
45       return "[" ~ prettyParams(param.get!XmlRpcArray) ~ "]";
46 
47    if (param.convertsTo!XmlRpcStruct) {
48       string output;
49       foreach (key, value; param.get!XmlRpcStruct) {
50          output ~= output ? ", " : "[";
51          output ~= "\"" ~ key ~ "\": " ~ prettyParam(value);
52       }
53       return output ~ "]";
54    }
55 
56    return to!string(param);
57 }
58 
59 version (xmlrpc_unittest) unittest {
60    import std.stdio;
61    import std.exception;
62 
63    auto call = MethodCallData("method", [Variant(123), Variant(["key" : Variant(cast(ubyte[]) x"dead")]),
64       Variant(cast(const ubyte[]) x"cafe")]);
65    //writeln(call.toString());
66    assert(call.toString() == `method(123, ["key": hex: de ad], hex: ca fe)`);
67 }