aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/protobuf/util/simple_reflection.cpp
blob: d842e9ee44d55c09ffdfa67cf4f4cf7651e746ba (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
#include "simple_reflection.h"

namespace NProtoBuf {
    const Message* GetMessageHelper(const TConstField& curField, bool) {
        return curField.HasValue() && curField.IsMessage() ? curField.Get<Message>() : nullptr;
    }

    Message* GetMessageHelper(TMutableField& curField, bool createPath) {
        if (curField.IsMessage()) {
            if (!curField.HasValue()) {
                if (createPath)
                    return curField.Field()->is_repeated() ? curField.AddMessage() : curField.MutableMessage();
            } else {
                return curField.MutableMessage();
            }
        }
        return nullptr;
    }

    template <class TField, class TMsg>
    TMaybe<TField> ByPathImpl(TMsg& msg, const TVector<const FieldDescriptor*>& fieldsPath, bool createPath) {
        if (fieldsPath.empty())
            return TMaybe<TField>();
        TMsg* curParent = &msg;
        for (size_t i = 0, size = fieldsPath.size(); i < size; ++i) {
            const FieldDescriptor* field = fieldsPath[i];
            if (!curParent)
                return TMaybe<TField>();
            TField curField(*curParent, field);
            if (size - i == 1) // last element in path
                return curField;
            curParent = GetMessageHelper(curField, createPath);
        }
        if (curParent)
            return TField(*curParent, fieldsPath.back());
        else
            return TMaybe<TField>();
    }

    TMaybe<TConstField> TConstField::ByPath(const Message& msg, const TVector<const FieldDescriptor*>& fieldsPath) {
        return ByPathImpl<TConstField, const Message>(msg, fieldsPath, false);
    }

    TMaybe<TConstField> TConstField::ByPath(const Message& msg, const TStringBuf& path) {
        TFieldPath fieldPath;
        if (!fieldPath.InitUnsafe(msg.GetDescriptor(), path))
            return TMaybe<TConstField>();
        return ByPathImpl<TConstField, const Message>(msg, fieldPath.Fields(), false);
    }

    TMaybe<TConstField> TConstField::ByPath(const Message& msg, const TFieldPath& path) {
        return ByPathImpl<TConstField, const Message>(msg, path.Fields(), false);
    }

    TMaybe<TMutableField> TMutableField::ByPath(Message& msg, const TVector<const FieldDescriptor*>& fieldsPath, bool createPath) {
        return ByPathImpl<TMutableField, Message>(msg, fieldsPath, createPath);
    }

    TMaybe<TMutableField> TMutableField::ByPath(Message& msg, const TStringBuf& path, bool createPath) {
        TFieldPath fieldPath;
        if (!fieldPath.InitUnsafe(msg.GetDescriptor(), path))
            return TMaybe<TMutableField>();
        return ByPathImpl<TMutableField, Message>(msg, fieldPath.Fields(), createPath);
    }

    TMaybe<TMutableField> TMutableField::ByPath(Message& msg, const TFieldPath& path, bool createPath) {
        return ByPathImpl<TMutableField, Message>(msg, path.Fields(), createPath);
    }

}