aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/util/jsonstream.h
blob: 183c8ba046c9a95b6cdd6a82266e2686f20fccb8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once

/**
 * An overbuild of the json writer, making the code writing the json looking
 * neater. Also allows templates to use it with unknown (but supported) types,
 * letting the compiler take care of calling the correct function rather than
 * having to resort to template specialization.
 */

#include <vespa/vespalib/util/jsonwriter.h>

namespace vespalib {

// Inherit to refer to types without namespace prefix in header file.
struct JsonStreamTypes {
    class Object {};
    class Array {};
    class End {};
};
// Use namespace in function to avoid prefixing namespace everywhere.
namespace jsonstream {
    using Object = JsonStreamTypes::Object;
    using Array = JsonStreamTypes::Array;
    using End = JsonStreamTypes::End;
}

// We can disable this if it ends up being a performance issue.
// Really useful to explain what code bits have tried to write invalid json
// though.
#define TRACK_JSON_CREATION_TO_CREATE_EASY_TO_DEBUG_ERROR_MESSAGES 1

class JsonStream : public JsonStreamTypes {
    JSONWriter _writer;
    enum class State {
        ROOT,
        OBJECT_EXPECTING_KEY,
        OBJECT_EXPECTING_VALUE,
        ARRAY
    };
    static const char* getStateName(const State&);
    struct StateEntry {
        State state;
        string object_key;
        size_t array_index;

        StateEntry() noexcept;
        StateEntry(State s) noexcept;
        StateEntry(State s, stringref key) noexcept;
        StateEntry(const StateEntry &) noexcept;
        StateEntry & operator =(const StateEntry &) noexcept;
        ~StateEntry();
    };
    std::vector<StateEntry> _state;

    StateEntry & top() { return _state.back(); }
    const StateEntry & top() const { return _state.back(); }
    void pop() { _state.resize(_state.size() - 1); }
    void push(const StateEntry & e) { _state.push_back(e); }
public:
    JsonStream(asciistream&, bool createIndents = false);
    JsonStream(const JsonStream&) = delete;
    JsonStream& operator=(const JsonStream&) = delete;
    JsonStream(JsonStream &&) = default;
    JsonStream& operator=(JsonStream &&) = default;
    ~JsonStream();

    JsonStream& operator<<(stringref);
    JsonStream& operator<<(bool);
    JsonStream& operator<<(double);
    JsonStream& operator<<(float); // Less precision that double
    JsonStream& operator<<(long long);
    JsonStream& operator<<(unsigned long long);
    JsonStream& operator<<(const Object&);
    JsonStream& operator<<(const Array&);
    JsonStream& operator<<(const End&);

        // Additional functions provided to let compiler work out correct
        // function without requiring user to cast their value
    JsonStream& operator<<(unsigned long v)
        { return operator<<(static_cast<unsigned long long>(v)); }
    JsonStream& operator<<(unsigned int v)
        { return operator<<(static_cast<unsigned long long>(v)); }
    JsonStream& operator<<(long v)
        { return operator<<(static_cast<long long>(v)); }
    JsonStream& operator<<(int v)
        { return operator<<(static_cast<long long>(v)); }
    JsonStream& operator<<(const char* c)
        { return operator<<(stringref(c)); }

    JsonStream& finalize();

    vespalib::string getJsonStreamState() const;

private:
    string getStateString() const;
    void fail(stringref error) const;
};

} // vespalib