Line data Source code
1 : /*
2 : * Copyright (c) 2025 Project CHIP Authors
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 <app/AttributeValueDecoder.h>
19 : #include <app/ConcreteAttributePath.h>
20 : #include <app/data-model-provider/ActionReturnStatus.h>
21 : #include <app/persistence/AttributePersistenceProvider.h>
22 : #include <app/persistence/String.h>
23 :
24 : #include <type_traits>
25 :
26 : namespace chip::app {
27 :
28 : /// Provides functionality for handling attribute persistence via
29 : /// an AttributePersistenceProvider.
30 : ///
31 : /// AttributePersistenceProvider works with raw bytes, however attributes
32 : /// have known (strong) types and their load/decode logic is often
33 : /// similar and reusable. This class implements the logic of handling
34 : /// such attributes, so that it can be reused across cluster implementations.
35 : class AttributePersistence
36 : {
37 : public:
38 5 : AttributePersistence(AttributePersistenceProvider & provider) : mProvider(provider) {}
39 :
40 : /// Loads a native-endianness stored value of type `T` into `value` from the persistence provider.
41 : ///
42 : /// If load fails, `false` is returned and data is filled with `valueOnLoadFailure`.
43 : ///
44 : /// Error reason for load failure is logged (or nothing logged in case "Value not found" is the
45 : /// reason for the load failure).
46 : template <typename T, typename std::enable_if_t<std::is_arithmetic_v<T> || std::is_enum_v<T>> * = nullptr>
47 7 : bool LoadNativeEndianValue(const ConcreteAttributePath & path, T & value, const T & valueOnLoadFailure)
48 : {
49 7 : return InternalRawLoadNativeEndianValue(path, &value, &valueOnLoadFailure, sizeof(T));
50 : }
51 :
52 : /// Performs all the steps of:
53 : /// - decode the given raw data
54 : /// - write to storage
55 : template <typename T, typename std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>
56 1 : CHIP_ERROR DecodeAndStoreNativeEndianValue(const ConcreteAttributePath & path, AttributeValueDecoder & decoder, T & value)
57 : {
58 1 : ReturnErrorOnFailure(decoder.Decode(value));
59 1 : return mProvider.WriteValue(path, { reinterpret_cast<const uint8_t *>(&value), sizeof(value) });
60 : }
61 :
62 : // Specialization for enums
63 : // - decode the given data
64 : // - verifies that it is a valid enum value
65 : // - writes to storage
66 : template <typename T, typename std::enable_if_t<std::is_enum_v<T>> * = nullptr>
67 2 : CHIP_ERROR DecodeAndStoreNativeEndianValue(const ConcreteAttributePath & path, AttributeValueDecoder & decoder, T & value)
68 : {
69 2 : T decodedValue = T::kUnknownEnumValue;
70 2 : ReturnErrorOnFailure(decoder.Decode(decodedValue));
71 2 : VerifyOrReturnError(decodedValue != T::kUnknownEnumValue, CHIP_IM_GLOBAL_STATUS(ConstraintError));
72 1 : value = decodedValue;
73 1 : return mProvider.WriteValue(path, { reinterpret_cast<const uint8_t *>(&value), sizeof(value) });
74 : }
75 :
76 : /// Load the given string from concrete storage.
77 : ///
78 : /// NOTE: `value` is take as an internal short string to avoid the templates that Storage::String
79 : /// implies, however callers are generally expected to pass in a `Storage::String` value and
80 : /// not use internal classes directly.
81 : ///
82 : /// Returns true on success, false on failure. On failure the string is reset to empty.
83 : bool LoadString(const ConcreteAttributePath & path, Storage::Internal::ShortString & value);
84 :
85 : /// Store the given string in persistent storage.
86 : ///
87 : /// NOTE: `value` is take as an internal short string to avoid the templates that Storage::String
88 : /// implies, however callers are generally expected to pass in a `Storage::String` value and
89 : /// not use internal classes directly.
90 : CHIP_ERROR StoreString(const ConcreteAttributePath & path, const Storage::Internal::ShortString & value);
91 :
92 : private:
93 : AttributePersistenceProvider & mProvider;
94 :
95 : /// Loads a raw value of size `size` into the memory pointed to by `data`.
96 : /// If load fails, `false` is returned and data is filled with `valueOnLoadFailure`.
97 : ///
98 : /// Error reason for load failure is logged (or nothing logged in case "Value not found" is the
99 : /// reason for the load failure).
100 : bool InternalRawLoadNativeEndianValue(const ConcreteAttributePath & path, void * data, const void * valueOnLoadFailure,
101 : size_t size);
102 : };
103 :
104 : } // namespace chip::app
|