xref: /aosp_15_r20/external/executorch/backends/apple/coreml/runtime/util/objc_json_serde.h (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
1 //
2 //  objc_json_serde.h
3 //  util
4 //
5 // Copyright © 2024 Apple Inc. All rights reserved.
6 //
7 // Please refer to the license found in the LICENSE file in the root directory of the source tree.
8 
9 #pragma once
10 
11 #import <Foundation/Foundation.h>
12 
13 #import <map>
14 #import <string>
15 #import <unordered_map>
16 #import <vector>
17 
18 #import <objc_safe_cast.h>
19 
20 namespace executorchcoreml {
21 namespace serde {
22 namespace json {
23 
to_string(std::string_view view)24 inline NSString* to_string(std::string_view view) { return @(std::string(view).c_str()); }
25 
26 template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
27 T to_scalar(NSNumber* value);
28 
to_scalar(NSNumber * value)29 template <> inline size_t to_scalar(NSNumber* value) { return value.unsignedLongLongValue; }
30 
to_scalar(NSNumber * value)31 template <> inline int64_t to_scalar(NSNumber* value) { return value.longLongValue; }
32 
33 id to_json_object(const std::string& json_string);
34 
35 id to_json_object(NSData* data);
36 
37 std::string to_json_string(id json_object);
38 
39 template <typename T, typename Enable = void> struct Converter { };
40 
41 template <typename T>
42 using is_vector =
43     std::is_same<std::decay_t<T>,
44                  std::vector<typename std::decay_t<T>::value_type, typename std::decay_t<T>::allocator_type>>;
45 
46 template <typename T>
47 using is_unordered_map = std::is_same<std::decay_t<T>,
48                                       std::unordered_map<typename std::decay_t<T>::key_type,
49                                                          typename std::decay_t<T>::mapped_type,
50                                                          typename std::decay_t<T>::hasher,
51                                                          typename std::decay_t<T>::key_equal,
52                                                          typename std::decay_t<T>::allocator_type>>;
53 
54 template <typename T> struct Converter<T, typename std::enable_if<std::is_arithmetic_v<T>>::type> {
55     template <typename U = T> static id to_json(U&& value) { return @(value); }
56 
57     static void from_json(id json_value, T& value) {
58         NSNumber* json_number = SAFE_CAST(json_value, NSNumber);
59         if (json_number) {
60             value = to_scalar<T>(json_number);
61         }
62     }
63 };
64 
65 template <typename T> struct Converter<T, typename std::enable_if<std::is_same_v<T, std::string>>::type> {
66     template <typename U = T> static id to_json(U&& value) { return @(value.c_str()); }
67 
68     static void from_json(id json_value, T& value) {
69         NSString* json_string = SAFE_CAST(json_value, NSString);
70         if (json_string) {
71             value = json_string.UTF8String;
72         }
73     }
74 };
75 
76 template <typename T> struct Converter<T, typename std::enable_if<is_vector<T>::value>::type> {
77     using value_type = typename T::value_type;
78 
79     template <typename U = T> static id to_json(U&& values) {
80         NSMutableArray<id>* result = [NSMutableArray arrayWithCapacity:values.size()];
81         for (auto it = values.begin(); it != values.end(); ++it) {
82             [result addObject:Converter<value_type>::to_json(*it)];
83         }
84 
85         return result;
86     }
87 
88     static void from_json(id json_value, T& values) {
89         NSArray<id>* json_values = SAFE_CAST(json_value, NSArray);
90         for (id json_object in json_values) {
91             value_type value;
92             Converter<value_type>::from_json(json_object, value);
93             values.emplace_back(std::move(value));
94         }
95     }
96 };
97 
98 template <typename T> struct Converter<T, std::enable_if_t<is_unordered_map<T>::value>> {
99     using value_type = typename T::mapped_type;
100     using key_type = typename T::key_type;
101 
102     static_assert(std::is_same<key_type, std::string>::value, "key_type must be string");
103 
104     template <typename U = T> static id to_json(U&& values) {
105         NSMutableDictionary<NSString*, id>* result = [NSMutableDictionary dictionaryWithCapacity:values.size()];
106         for (auto it = values.begin(); it != values.end(); ++it) {
107             result[@(it->first.c_str())] = Converter<value_type>::to_json(it->second);
108         }
109 
110         return result;
111     }
112 
113     static void from_json(id json_value, T& values) {
114         NSDictionary<NSString*, id>* json_values = SAFE_CAST(json_value, NSDictionary);
115         for (NSString* key in json_values) {
116             value_type value;
117             Converter<value_type>::from_json(json_values[key], value);
118             values.emplace(std::string(key.UTF8String), std::move(value));
119         }
120     }
121 };
122 
123 template <typename T> inline id to_json_value(T&& value) {
124     return Converter<typename std::decay_t<T>>::to_json(std::forward<T>(value));
125 }
126 
127 template <typename T> void from_json_value(id json_value, T& value) {
128     return Converter<T>::from_json(json_value, value);
129 }
130 
131 } // namespace serde
132 } // namespace json
133 } // namespace executorchcoreml
134