aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/types/binary_json/read.h
blob: c9b2c1cbf0bb39da01eb47427c447b258a04f60f (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#pragma once

#include "format.h"

#include <yql/essentials/minikql/dom/node.h>

#include <util/system/unaligned_mem.h>
#include <util/generic/ptr.h>
#include <util/generic/maybe.h>
#include <util/string/builder.h>

namespace NKikimr::NBinaryJson {

class TContainerCursor;

/**
 * @brief Reads values inside BinaryJson. `Read...` methods of this class are not intended for direct use.
 * Consider using `GetRootCursor` method to get more convenient interface over BinaryJson data
 */
class TBinaryJsonReader : public TSimpleRefCount<TBinaryJsonReader> {
public:
    template <typename... Args>
    static TIntrusivePtr<TBinaryJsonReader> Make(Args&&... args) {
        return new TBinaryJsonReader{std::forward<Args>(args)...};
    }

    TContainerCursor GetRootCursor();

    TMeta ReadMeta(ui32 offset) const;

    TEntry ReadEntry(ui32 offset) const;

    TKeyEntry ReadKeyEntry(ui32 offset) const;

    /**
     * @brief Reads string from String index
     *
     * @param offset Offset to the beginning of TSEntry
     */
    const TStringBuf ReadString(ui32 offset) const;

    /**
     * @brief Reads number from Number index
     *
     * @param offset Offset to the beginning of number
     */
    double ReadNumber(ui32 offset) const;

private:
    explicit TBinaryJsonReader(const TBinaryJson& buffer);

    explicit TBinaryJsonReader(TStringBuf buffer);

    template <typename T>
    T ReadPOD(ui32 offset) const {
        static_assert(std::is_pod_v<T>, "Type must be POD");
        Y_ENSURE(offset + sizeof(T) <= Buffer.size(),
            TStringBuilder() << "Not enough space in buffer to read value (" << offset << " + " << sizeof(T) << " > " << Buffer.size() << ")");
        return ReadUnaligned<T>(Buffer.data() + offset);
    }

    TStringBuf Buffer;
    THeader Header;
    ui32 TreeStart;
    ui32 StringSEntryStart;
    ui32 StringCount;
};

using TBinaryJsonReaderPtr = TIntrusivePtr<TBinaryJsonReader>;

/**
 * @brief Interface to single TEntry inside BinaryJson
 */
class TEntryCursor {
public:
    TEntryCursor(TBinaryJsonReaderPtr reader, TEntry entry);

    EEntryType GetType() const;

    TContainerCursor GetContainer() const;

    TStringBuf GetString() const;

    double GetNumber() const;

private:
    TBinaryJsonReaderPtr Reader;
    TEntry Entry;
};

/**
 * @brief Iterator to walk through array elements
 */
class TArrayIterator {
public:
    TArrayIterator(TBinaryJsonReaderPtr reader, ui32 startOffset, ui32 count);

    TEntryCursor Next();

    bool HasNext() const;

private:
    TBinaryJsonReaderPtr Reader;
    ui32 Offset;
    ui32 EndOffset;
};

/**
 * @brief Iterator to walk through object key-value pairs
 */
class TObjectIterator {
public:
    TObjectIterator(TBinaryJsonReaderPtr reader, ui32 startOffset, ui32 count);

    std::pair<TEntryCursor, TEntryCursor> Next();

    bool HasNext() const;

private:
    TBinaryJsonReaderPtr Reader;
    ui32 KeyOffset;
    ui32 ValueOffset;
    ui32 ValueEndOffset;
};

/**
 * @brief Interface to container inside BinaryJson
 */
class TContainerCursor {
public:
    TContainerCursor(TBinaryJsonReaderPtr reader, ui32 startOffset);

    EContainerType GetType() const;

    /**
     * @brief Get container size. Array length for arrays and count of unique keys for objects
     */
    ui32 GetSize() const;

    /**
     * @brief Get array element at specified index
     */
    TEntryCursor GetElement(ui32 index) const;

    /**
     * @brief Get iterator to array elements
     */
    TArrayIterator GetArrayIterator() const;

    /**
     * @brief Get value corresponding to given key in object
     */
    TMaybe<TEntryCursor> Lookup(const TStringBuf key) const;

    /**
     * @brief Get iterator to object key-value pairs
     */
    TObjectIterator GetObjectIterator() const;

private:
    TBinaryJsonReaderPtr Reader;
    ui32 StartOffset;
    TMeta Meta;
};

NUdf::TUnboxedValue ReadContainerToJsonDom(const TContainerCursor& cursor, const NUdf::IValueBuilder* valueBuilder);

NUdf::TUnboxedValue ReadElementToJsonDom(const TEntryCursor& cursor, const NUdf::IValueBuilder* valueBuilder);

/**
 * @brief Reads whole BinaryJson into TUnboxedValue using DOM layout from `yql/library/dom` library
 */
NUdf::TUnboxedValue ReadToJsonDom(const TBinaryJson& binaryJson, const NUdf::IValueBuilder* valueBuilder);

NUdf::TUnboxedValue ReadToJsonDom(TStringBuf binaryJson, const NUdf::IValueBuilder* valueBuilder);

/**
 * @brief Serializes whole BinaryJson into textual JSON
 */
TString SerializeToJson(const TBinaryJson& binaryJson);

TString SerializeToJson(TStringBuf binaryJson);

bool IsValidBinaryJson(TStringBuf buffer);

TMaybe<TStringBuf> IsValidBinaryJsonWithError(TStringBuf buffer);

}