1 // Copyright 2020 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 <cstdint> 17 #include <limits> 18 19 #include "pw_containers/intrusive_list.h" 20 #include "pw_preprocessor/compiler.h" 21 #include "pw_rpc/internal/method.h" 22 #include "pw_rpc/internal/method_union.h" 23 #include "pw_rpc/service_id.h" 24 #include "pw_span/span.h" 25 26 namespace pw::rpc { 27 28 // Base class for all RPC services. This cannot be instantiated directly; use a 29 // generated subclass instead. 30 // 31 // Services store a span of concrete method implementation classes. To support 32 // different Method implementations, Service stores a base MethodUnion* and the 33 // size of the concrete MethodUnion object. 34 class Service : public IntrusiveList<Service>::Item { 35 public: 36 Service(const Service&) = delete; 37 Service(Service&&) = delete; 38 39 Service& operator=(const Service&) = delete; 40 Service& operator=(Service&&) = delete; 41 service_id()42 ServiceId service_id() const { return internal::WrapServiceId(id_); } 43 44 protected: 45 // Note: despite being non-`::internal` and non-`private`, this constructor 46 // is not considered part of pigweed's public API: calling it requires 47 // constructing `methods`, which must have a `.data()` accessor which returns 48 // a `const internal::MethodUnion*`. 49 template <typename T, size_t kMethodCount> Service(uint32_t id,const std::array<T,kMethodCount> & methods)50 constexpr Service(uint32_t id, const std::array<T, kMethodCount>& methods) 51 : id_(id), 52 methods_(methods.data()), 53 method_size_(sizeof(T)), 54 method_count_(static_cast<uint16_t>(kMethodCount)) { 55 PW_MODIFY_DIAGNOSTICS_PUSH(); 56 // GCC 10 emits spurious -Wtype-limits warnings for the static_assert. 57 PW_MODIFY_DIAGNOSTIC_GCC(ignored, "-Wtype-limits"); 58 static_assert(kMethodCount <= std::numeric_limits<uint16_t>::max()); 59 PW_MODIFY_DIAGNOSTICS_POP(); 60 } 61 62 // For use by tests with only one method. 63 // 64 // Note: This constructor is not for direct use outside of pigweed, and 65 // is not considered part of the public API. 66 template <typename T> Service(uint32_t id,const T & method)67 constexpr Service(uint32_t id, const T& method) 68 : id_(id), methods_(&method), method_size_(sizeof(T)), method_count_(1) {} 69 70 private: 71 friend class Server; 72 friend class ServiceTestHelper; 73 74 // Finds the method with the provided method_id. Returns nullptr if no match. 75 const internal::Method* FindMethod(uint32_t method_id) const; 76 77 const uint32_t id_; 78 const internal::MethodUnion* const methods_; 79 const uint16_t method_size_; 80 const uint16_t method_count_; 81 }; 82 83 } // namespace pw::rpc 84