Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2020-2021 Project CHIP Authors 4 : * All rights reserved. 5 : * 6 : * Licensed under the Apache License, Version 2.0 (the "License"); 7 : * you may not use this file except in compliance with the License. 8 : * You may obtain a copy of the License at 9 : * 10 : * http://www.apache.org/licenses/LICENSE-2.0 11 : * 12 : * Unless required by applicable law or agreed to in writing, software 13 : * distributed under the License is distributed on an "AS IS" BASIS, 14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 : * See the License for the specific language governing permissions and 16 : * limitations under the License. 17 : */ 18 : 19 : #pragma once 20 : 21 : #include <app/util/attribute-storage-null-handling.h> 22 : #include <lib/core/Optional.h> 23 : 24 : #include <type_traits> 25 : 26 : namespace chip { 27 : namespace app { 28 : namespace DataModel { 29 : 30 : /** 31 : * NullNullable is an alias for NullOptional, for better readability. 32 : */ 33 : inline constexpr auto NullNullable = NullOptional; 34 : 35 : /* 36 : * Dedicated type for nullable things, to differentiate them from optional 37 : * things. 38 : */ 39 : template <typename T> 40 : struct Nullable : protected Optional<T> 41 : { 42 : // 43 : // The following 'using' statement is needed to make visible 44 : // all constructors of the base class within this derived class. 45 : // 46 : using Optional<T>::Optional; 47 : 48 : // Pull in APIs that make sense on Nullable with the same names as on 49 : // Optional. 50 : using Optional<T>::Value; 51 : using Optional<T>::ValueOr; 52 : 53 : // Some consumers need an easy way to determine our underlying type. 54 : using UnderlyingType = T; 55 : 56 4418 : constexpr void SetNull() { Optional<T>::ClearValue(); } 57 10122 : constexpr bool IsNull() const { return !Optional<T>::HasValue(); } 58 : 59 : template <class... Args> 60 0 : constexpr T & SetNonNull(Args &&... args) 61 : { 62 0 : return Optional<T>::Emplace(std::forward<Args>(args)...); 63 : } 64 : 65 : // For integer types, being nullable involves a range restriction. 66 : template < 67 : typename U = std::decay_t<T>, 68 : typename std::enable_if_t<(std::is_integral<U>::value && !std::is_same<U, bool>::value) || std::is_enum<U>::value, int> = 0> 69 : constexpr bool ExistingValueInEncodableRange() const 70 : { 71 : return NumericAttributeTraits<T>::CanRepresentValue(/* isNullable = */ true, Value()); 72 : } 73 : 74 : // For all other types, all values are valid. 75 : template <typename U = std::decay_t<T>, 76 : typename std::enable_if_t<(!std::is_integral<U>::value || std::is_same<U, bool>::value) && !std::is_enum<U>::value, 77 : int> = 0> 78 0 : constexpr bool ExistingValueInEncodableRange() const 79 : { 80 0 : return true; 81 : } 82 : 83 : // The only fabric-scoped objects in the spec are commands, events and structs inside lists, and none of those can be nullable. 84 : static constexpr bool kIsFabricScoped = false; 85 : 86 : bool operator==(const Nullable & other) const { return Optional<T>::operator==(other); } 87 18 : bool operator!=(const Nullable & other) const { return Optional<T>::operator!=(other); } 88 : bool operator==(const T & other) const { return Optional<T>::operator==(other); } 89 : bool operator!=(const T & other) const { return Optional<T>::operator!=(other); } 90 : }; 91 : 92 : template <class T> 93 4 : constexpr Nullable<std::decay_t<T>> MakeNullable(T && value) 94 : { 95 4 : return Nullable<std::decay_t<T>>(InPlace, std::forward<T>(value)); 96 : } 97 : 98 : template <class T, class... Args> 99 : constexpr Nullable<T> MakeNullable(Args &&... args) 100 : { 101 : return Nullable<T>(InPlace, std::forward<Args>(args)...); 102 : } 103 : 104 : } // namespace DataModel 105 : } // namespace app 106 : } // namespace chip