/* * Copyright (c) 2014, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following * disclaimer in the documentation and/or other materials provided with the * distribution. * * Neither the name of the Ford Motor Company nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef SRC_COMPONENTS_RPC_BASE_INCLUDE_RPC_BASE_RPC_BASE_INL_H_ #define SRC_COMPONENTS_RPC_BASE_INCLUDE_RPC_BASE_RPC_BASE_INL_H_ #include "rpc_base.h" #include #include #include "rpc_base/validation_report.h" namespace rpc { /* * Range helper class */ template Range::Range(T min, T max) : min_(min), max_(max) {} template T Range::min() const { return min_; } template T Range::max() const { return max_; } template template bool Range::Includes(U val) const { return min() <= val && val <= max(); } /* * PrimitiveType base class */ inline PrimitiveType::PrimitiveType(ValueState value_state) : value_state_(value_state) , policy_table_type_(policy_table_interface_base::PT_PRELOADED) {} inline bool PrimitiveType::is_initialized() const { return value_state_ != kUninitialized; } inline bool PrimitiveType::is_valid() const { return value_state_ == kValid; } inline void PrimitiveType::ReportErrors(ValidationReport* report) const { switch (value_state_) { case kUninitialized: { report->set_validation_info("value is not initialized"); break; } case kInvalid: { report->set_validation_info("value initialized incorrectly"); break; } case kValid: { // No error break; } default: { assert(!"Unexpected value state"); break; } } } /* * CompositeType base class */ inline void CompositeType::mark_initialized() { initialization_state__ = kInitialized; } inline CompositeType::CompositeType(InitializationState init_state) : initialization_state__(init_state) , policy_table_type_(policy_table_interface_base::PT_PRELOADED) {} inline void CompositeType::ReportErrors(ValidationReport* report) const { switch (initialization_state__) { case kUninitialized: { report->set_validation_info("object is not initialized"); break; } case kInvalidInitialized: { report->set_validation_info("object initialized incorrectly"); break; } case kInitialized: { // No error break; } default: assert(!"Unexpected initialization state"); break; } } /* * Boolean class */ inline Boolean::Boolean() : PrimitiveType(kUninitialized), value_(false) {} inline Boolean::Boolean(bool value) : PrimitiveType(kValid), value_(value) {} inline Boolean& Boolean::operator=(bool new_val) { value_ = new_val; value_state_ = kValid; return *this; } inline Boolean::operator bool() const { return value_; } /* * Integer class */ template const Range Integer::range_(minval, maxval); template Integer::Integer() : PrimitiveType(kUninitialized), value_(range_.min()) {} template Integer::Integer(IntType value) : PrimitiveType(range_.Includes(value) ? kValid : kInvalid) , value_(value) {} template Integer& Integer::operator=( IntType new_val) { value_ = new_val; value_state_ = range_.Includes(value_) ? kValid : kInvalid; return *this; } template Integer& Integer::operator=( const Integer& new_val) { this->value_ = new_val.value_; if (new_val.is_initialized()) { this->value_state_ = new_val.value_state_; } return *this; } template Integer& Integer::operator++() { ++value_; return *this; } template Integer& Integer::operator+=(int value) { value_ += value; return *this; } template Integer::operator IntType() const { return value_; } /* * Float class */ template const Range Float::range_( (double(minnum) / minden), (double(maxnum) / maxden)); template Float::Float() : PrimitiveType(kUninitialized), value_(range_.min()) {} template Float::Float(double value) : PrimitiveType(range_.Includes(value) ? kValid : kInvalid) , value_(value) {} template Float& Float:: operator=(double new_val) { value_ = new_val; value_state_ = range_.Includes(new_val) ? kValid : kInvalid; return *this; } template Float::operator double() const { return value_; } /* * String class */ template const Range String::length_range_(minlen, maxlen); template String::String() : PrimitiveType(kUninitialized) {} template String::String(const std::string& value) : PrimitiveType(length_range_.Includes(value.length()) ? kValid : kInvalid) , value_(value) {} template String::String(const char* value) : PrimitiveType(kUninitialized), value_(value) { value_state_ = length_range_.Includes(value_.length()) ? kValid : kInvalid; } template bool String::operator<(const String& new_val) const { return value_ < new_val.value_; } template String& String::operator=( const std::string& new_val) { value_ = new_val; value_state_ = length_range_.Includes(new_val.length()) ? kValid : kInvalid; return *this; } template String& String::operator=( const String& new_val) { if (*this == new_val) { return *this; } value_.assign(new_val.value_); value_state_ = new_val.value_state_; return *this; } template bool String::operator==(const String& rhs) const { return value_ == rhs.value_; } template String::operator const std::string&() const { return value_; } /* * Enum class */ template Enum::Enum() : PrimitiveType(kUninitialized), value_(EnumType()) {} template Enum::Enum(EnumType value) : PrimitiveType(IsValidEnum(value) ? kValid : kInvalid), value_(value) {} template Enum& Enum::operator=(const EnumType& new_val) { value_ = new_val; value_state_ = IsValidEnum(value_) ? kValid : kInvalid; return *this; } template Enum::operator EnumType() const { return value_; } /* * Array class */ template Array::Array() : CompositeType(kUninitialized) {} template template Array::Array(const U& value) : ArrayType(value.begin(), value.end()), CompositeType(kUninitialized) {} template template Array& Array::operator=( const U& that) { this->assign(that.begin(), that.end()); return *this; } template template void Array::push_back(const U& value) { ArrayType::push_back(T(value)); } template bool Array::is_valid() const { // Empty array might be valid only if marked initialized if (this->empty() && (initialization_state__ != kInitialized)) { return false; } // Array size must be within allowed range if (!Range(minsize, maxsize).Includes(this->size())) { return false; } // All array elements must be valid for (typename ArrayType::const_iterator i = this->begin(); i != this->end(); ++i) { if (!i->is_valid()) { return false; } } return true; } template bool Array::is_initialized() const { // Array that is not empty is initialized for sure if (!this->empty()) { return true; } // Empty array is initialized if not marked as unitialized if (initialization_state__ != kUninitialized) { return true; } return false; } template void Array::ReportErrors(ValidationReport* report) const { if (this->empty()) { CompositeType::ReportErrors(report); } else { if (!Range(minsize, maxsize).Includes(this->size())) { report->set_validation_info("array has invalid size"); } else { // No error } } for (size_t i = 0; i != this->size(); ++i) { const T& elem = this->operator[](i); if (!elem.is_valid()) { char elem_idx[32] = {}; snprintf(elem_idx, 32, "[%zu]", i); ValidationReport& elem_report = report->ReportSubobject(elem_idx); elem.ReportErrors(&elem_report); } } } template void Array::SetPolicyTableType( rpc::policy_table_interface_base::PolicyTableType pt_type) { for (typename ArrayType::iterator it = this->begin(); it != this->end(); ++it) { it->SetPolicyTableType(pt_type); } } /* * Map class */ template Map::Map() : CompositeType(kUninitialized) {} template template Map::Map(const U& value) : CompositeType(kUninitialized) { for (typename U::const_iterator i = value.begin(), e = value.end(); i != e; ++i) { // Explicitly convert that value to T because all rpc_types have explicit // constructors insert(typename MapType::value_type(i->first, T(i->second))); } } template template Map& Map::operator=(const U& that) { this->clear(); for (typename U::const_iterator i = that.begin(), e = that.end(); i != e; ++i) { // Explicitly convert that value to T because all rpc_types have explicit // constructors insert(typename MapType::value_type(i->first, T(i->second))); } return *this; } template template void Map::insert(const std::pair& value) { MapType::insert(typename MapType::value_type(value.first, T(value.second))); } template bool Map::is_valid() const { // Empty map might be valid only if marked initialized if (this->empty() && (initialization_state__ != kInitialized)) { return false; } // Maps size must be within allowed range if (!Range(minsize, maxsize).Includes(this->size())) { return false; } // All map elements must be valid for (typename Map::const_iterator i = this->begin(); i != this->end(); ++i) { if (!i->second.is_valid()) { return false; } } return true; } template bool Map::is_initialized() const { // Map that is not empty is initialized for sure if (!this->empty()) { return true; } // Empty map might be initialized only if not marked as unitialized if (initialization_state__ != kUninitialized) { return true; } return false; } template void Map::ReportErrors(ValidationReport* report) const { if (this->empty()) { CompositeType::ReportErrors(report); } else { if (!Range(minsize, maxsize).Includes(this->size())) { report->set_validation_info("map has invalid size"); } else { // No error } } for (typename Map::const_iterator i = this->begin(); i != this->end(); ++i) { if (!i->second.is_valid()) { std::string elem_name = "[\"" + i->first + "\"]"; ValidationReport& elem_report = report->ReportSubobject(elem_name); i->second.ReportErrors(&elem_report); } } } template void Map::SetPolicyTableType( rpc::policy_table_interface_base::PolicyTableType pt_type) { for (typename Map::iterator it = this->begin(); it != this->end(); ++it) { it->second.SetPolicyTableType(pt_type); } } /* * Nullable class */ template Nullable::Nullable() : marked_null_(false) {} template template Nullable::Nullable(const U& value) : T(value), marked_null_(false) {} template template Nullable& Nullable::operator=(const U& new_val) { this->T::operator=(new_val); return *this; } template bool Nullable::is_valid() const { return is_null() || T::is_valid(); } template bool Nullable::is_initialized() const { return is_null() || T::is_initialized(); } template bool Nullable::is_null() const { return marked_null_; } template void Nullable::set_to_null() { marked_null_ = true; } template void Nullable::ReportErrors(ValidationReport* report) const { if (marked_null_) { // No error } else { T::ReportErrors(report); } } /* * Optional class */ template Optional::Optional() {} template template Optional::Optional(const U& value) : value_(value) {} template T& Optional::operator*() { return value_; } template const T& Optional::operator*() const { return value_; } template T* Optional::operator->() { return &value_; } template const T* Optional::operator->() const { return &value_; } template void Optional::assign_if_valid(const Optional& value) { if (value.is_initialized()) { value_ = value.value_; } } template Optional::operator const void*() const { return is_initialized() ? &value_ : NULL; } template bool Optional::is_valid() const { return !value_.is_initialized() || value_.is_valid(); } template bool Optional::is_initialized() const { return value_.is_initialized(); } template void Optional::ReportErrors(ValidationReport* report) const { if (!is_initialized()) { // No error } else { value_.ReportErrors(report); } } template inline rpc::policy_table_interface_base::PolicyTableType Optional::GetPolicyTableType() const { return policy_table_type_; } template void rpc::Optional::SetPolicyTableType( rpc::policy_table_interface_base::PolicyTableType pt_type) { policy_table_type_ = pt_type; value_.SetPolicyTableType(pt_type); } /* * Stringifyable class */ template Stringifyable::Stringifyable() : predefined_string_("") {} template template Stringifyable::Stringifyable(const U& value) : T(value), predefined_string_("") {} template template Stringifyable& Stringifyable::operator=(const U& new_val) { this->T::operator=(new_val); return *this; } template bool Stringifyable::is_valid() const { return is_string() || T::is_valid(); } template bool Stringifyable::is_initialized() const { return is_string() || T::is_initialized(); } template bool Stringifyable::is_string() const { return !predefined_string_.empty(); } template std::string Stringifyable::get_string() const { return predefined_string_; } template void Stringifyable::set_to_string(const std::string& input) { predefined_string_ = input; } template void Stringifyable::ReportErrors(ValidationReport* report) const { if (is_string()) { // No error } else { T::ReportErrors(report); } } } // namespace rpc #endif // SRC_COMPONENTS_RPC_BASE_INCLUDE_RPC_BASE_RPC_BASE_INL_H_