1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <cstdint>
19 #include <limits>
20 #include <optional>
21 #include <type_traits>
22 
23 #include "common/numbers.h"
24 #include "common/strings.h"
25 #include "common/type_helper.h"
26 #include "hci/enum_helper.h"
27 #include "storage/config_cache.h"
28 #include "storage/mutation_entry.h"
29 #include "storage/serializable.h"
30 
31 namespace bluetooth {
32 namespace storage {
33 
34 // A thin wrapper around ConfigCache and implement more type supports other than std::string
35 //
36 // - all SetX methods accept value as copy and std::move() in encouraged
37 // - all GetX methods return std::optional<X> and std::nullopt if not exist. std::optional<> can be treated as bool
38 class ConfigCacheHelper {
39  public:
FromConfigCache(ConfigCache & config_cache)40   static ConfigCacheHelper FromConfigCache(ConfigCache& config_cache) {
41     return ConfigCacheHelper(config_cache);
42   }
ConfigCacheHelper(ConfigCache & config_cache)43   explicit ConfigCacheHelper(ConfigCache& config_cache) : config_cache_(config_cache) {}
44   virtual ~ConfigCacheHelper() = default;
45   virtual void SetBool(const std::string& section, const std::string& property, bool value);
46   virtual std::optional<bool> GetBool(const std::string& section, const std::string& property) const;
47   virtual void SetUint64(const std::string& section, const std::string& property, uint64_t value);
48   virtual std::optional<uint64_t> GetUint64(const std::string& section, const std::string& property) const;
49   virtual void SetUint32(const std::string& section, const std::string& property, uint32_t value);
50   virtual std::optional<uint32_t> GetUint32(const std::string& section, const std::string& property) const;
51   virtual void SetInt64(const std::string& section, const std::string& property, int64_t value);
52   virtual std::optional<int64_t> GetInt64(const std::string& section, const std::string& property) const;
53   virtual void SetInt(const std::string& section, const std::string& property, int value);
54   virtual std::optional<int> GetInt(const std::string& section, const std::string& property) const;
55   virtual void SetBin(const std::string& section, const std::string& property, const std::vector<uint8_t>& value);
56   virtual std::optional<std::vector<uint8_t>> GetBin(const std::string& section, const std::string& property) const;
57 
58   template <typename T, typename std::enable_if<std::is_signed_v<T> && std::is_integral_v<T>, int>::type = 0>
Get(const std::string & section,const std::string & property)59   std::optional<T> Get(const std::string& section, const std::string& property) {
60     auto value = GetInt64(section, property);
61     if (!value) {
62       return std::nullopt;
63     }
64     if (!common::IsNumberInNumericLimits<T>(*value)) {
65       return std::nullopt;
66     }
67     return static_cast<T>(*value);
68   }
69 
70   template <typename T, typename std::enable_if<std::is_unsigned_v<T> && std::is_integral_v<T>, int>::type = 0>
Get(const std::string & section,const std::string & property)71   std::optional<T> Get(const std::string& section, const std::string& property) {
72     auto value = GetUint64(section, property);
73     if (!value) {
74       return std::nullopt;
75     }
76     if (!common::IsNumberInNumericLimits<T>(*value)) {
77       return std::nullopt;
78     }
79     return static_cast<T>(*value);
80   }
81 
82   template <typename T, typename std::enable_if<std::is_same_v<T, std::string>, int>::type = 0>
Get(const std::string & section,const std::string & property)83   std::optional<T> Get(const std::string& section, const std::string& property) {
84     return config_cache_.GetProperty(section, property);
85   }
86 
87   template <typename T, typename std::enable_if<std::is_same_v<T, std::vector<uint8_t>>, int>::type = 0>
Get(const std::string & section,const std::string & property)88   std::optional<T> Get(const std::string& section, const std::string& property) {
89     return GetBin(section, property);
90   }
91 
92   template <typename T, typename std::enable_if<std::is_same_v<T, bool>, int>::type = 0>
Get(const std::string & section,const std::string & property)93   std::optional<T> Get(const std::string& section, const std::string& property) {
94     return GetBool(section, property);
95   }
96 
97   template <typename T, typename std::enable_if<std::is_base_of_v<Serializable<T>, T>, int>::type = 0>
Get(const std::string & section,const std::string & property)98   std::optional<T> Get(const std::string& section, const std::string& property) {
99     auto value = config_cache_.GetProperty(section, property);
100     if (!value) {
101       return std::nullopt;
102     }
103     return T::FromLegacyConfigString(*value);
104   }
105 
106   template <typename T, typename std::enable_if<std::is_enum_v<T>, int>::type = 0>
Get(const std::string & section,const std::string & property)107   std::optional<T> Get(const std::string& section, const std::string& property) {
108     auto value = config_cache_.GetProperty(section, property);
109     if (!value) {
110       return std::nullopt;
111     }
112     return bluetooth::FromLegacyConfigString<T>(*value);
113   }
114 
115   template <
116       typename T,
117       typename std::enable_if<
118           bluetooth::common::is_specialization_of<T, std::vector>::value &&
119               std::is_base_of_v<Serializable<typename T::value_type>, typename T::value_type>,
120           int>::type = 0>
Get(const std::string & section,const std::string & property)121   std::optional<T> Get(const std::string& section, const std::string& property) {
122     auto value = config_cache_.GetProperty(section, property);
123     if (!value) {
124       return std::nullopt;
125     }
126     auto values = common::StringSplit(*value, " ");
127     T result;
128     result.reserve(values.size());
129     for (const auto& str : values) {
130       auto v = T::value_type::FromLegacyConfigString(str);
131       if (!v) {
132         return std::nullopt;
133       }
134       result.push_back(*v);
135     }
136     return result;
137   }
138 
139  private:
140   ConfigCache& config_cache_;
141 };
142 
143 }  // namespace storage
144 }  // namespace bluetooth
145