1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #include <cstring>
17 #include <type_traits>
18
19 #include "pw_result/result.h"
20 #include "pw_span/span.h"
21 #include "pw_status/status.h"
22
23 namespace pw::bluetooth {
24
25 // Create an Emboss view and check that it is Ok().
26 // Returns Status::DataLoss() if the view is not Ok().
27 //
28 // The emboss type is determined by the template's first parameter.
29 template <typename EmbossT, typename... Params>
MakeEmbossView(Params &&...params)30 constexpr inline Result<EmbossT> MakeEmbossView(Params&&... params) {
31 auto view = EmbossT(std::forward<Params>(params)...);
32 if (view.Ok()) {
33 return view;
34 } else {
35 return Status::DataLoss();
36 }
37 }
38
39 // Create an Emboss View from a pw::span value or reference and check that it is
40 // Ok(). Returns Status::DataLoss() if the view is not Ok().
41 //
42 // The emboss type is determined by the template's first parameter.
43 // Unlike the Emboss `Make*View` creation methods, this function accepts a
44 // reference so it can be used with rvalues. This is ok to do with pw::span
45 // since it doesn't own its underlying data.
46 template <typename EmbossT,
47 typename ContainerT,
48 typename = std::enable_if_t<
49 std::is_convertible_v<ContainerT, pw::span<const uint8_t>>>>
MakeEmbossView(ContainerT && buffer)50 constexpr inline Result<EmbossT> MakeEmbossView(ContainerT&& buffer) {
51 return MakeEmbossView<EmbossT>(buffer.data(), buffer.size());
52 }
53
54 // Create an Emboss Writer and check that and check that the
55 // backing storage contains at least enough space for MinSizeInBytes().
56 // Returns Status::InvalidArgument() if the buffer isn't large enough for
57 // requested writer.
58 //
59 // The emboss type is determined by the template's first parameter.
60 template <typename EmbossT, typename... Params>
MakeEmbossWriter(Params &&...params)61 constexpr inline Result<EmbossT> MakeEmbossWriter(Params&&... params) {
62 auto view = EmbossT(std::forward<Params>(params)...);
63 if (view.BackingStorage().SizeInBytes() >=
64 static_cast<size_t>(EmbossT::MinSizeInBytes().Read())) {
65 return view;
66 } else {
67 return Status::InvalidArgument();
68 }
69 }
70
71 // Create an Emboss Writer from a pw::span value or reference and check that the
72 // backing storage contains at least enough space for MinSizeInBytes(). Returns
73 // Status::InvalidArgument() if the buffer isn't large enough for requested
74 // writer.
75 //
76 // The emboss type is determined by the template's first parameter.
77 // Unlike the Emboss `Make*View` creation methods, this function accepts a
78 // reference so it can be used with rvalues. This is ok to do with pw::span
79 // since it doesn't own its underlying data.
80 template <typename EmbossT,
81 typename ContainerT,
82 typename = std::enable_if_t<
83 std::is_convertible_v<ContainerT, pw::span<uint8_t>>>>
MakeEmbossWriter(ContainerT && buffer)84 constexpr inline Result<EmbossT> MakeEmbossWriter(ContainerT&& buffer) {
85 return MakeEmbossWriter<EmbossT>(buffer.data(), buffer.size());
86 }
87
88 /// Copy from a container to an Emboss object's backing storage.
89 ///
90 /// Container needs to support `data()` and `size()` (in bytes) functions.
91 template <typename EmbossT, typename ContainerT>
UncheckedCopyToEmbossStruct(EmbossT emboss_dest,ContainerT && src)92 constexpr void UncheckedCopyToEmbossStruct(EmbossT emboss_dest,
93 ContainerT&& src) {
94 // std::memcpy allows size zero, but ubsan will complain for some empty
95 // containers so just skip copy in those cases.
96 if (src.size() == 0) {
97 return;
98 }
99 std::memcpy(emboss_dest.BackingStorage().data(), src.data(), src.size());
100 }
101
102 /// Try to copy from a container to an Emboss object's backing storage.
103 ///
104 /// Returns false if the Emboss object is not Ok and or can't fit the
105 /// container's contents.
106 ///
107 /// Container needs to support `data()` and `size()` (in bytes) functions.
108 template <typename EmbossT, typename ContainerT>
TryToCopyToEmbossStruct(EmbossT emboss_dest,ContainerT && src)109 [[nodiscard]] constexpr bool TryToCopyToEmbossStruct(EmbossT emboss_dest,
110 ContainerT&& src) {
111 if (!emboss_dest.IsComplete() || src.size() > emboss_dest.SizeInBytes()) {
112 return false;
113 }
114 UncheckedCopyToEmbossStruct(emboss_dest, src);
115 return true;
116 }
117
118 } // namespace pw::bluetooth
119