• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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