// // Copyright (C) 2012 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #ifndef SHILL_PROPERTY_ACCESSOR_H_ #define SHILL_PROPERTY_ACCESSOR_H_ #include #include // for FRIEND_TEST. #include "shill/accessor_interface.h" #include "shill/error.h" #include "shill/logging.h" namespace shill { // Templated implementations of AccessorInterface<>. // // PropertyAccessor<>, ConstPropertyAccessor<>, and // WriteOnlyPropertyAccessor<> provide R/W, R/O, and W/O access // (respectively) to the value pointed to by |property|. // // This allows a class to easily map strings to member variables, so that // pieces of state stored in the class can be queried or updated by name. // // bool foo = true; // map accessors; // accessors["foo"] = BoolAccessor(new PropertyAccessor(&foo)); // bool new_foo = accessors["foo"]->Get(); // new_foo == true // accessors["foo"]->Set(false); // returns true, because setting is allowed. // // foo == false, new_foo == true // new_foo = accessors["foo"]->Get(); // new_foo == false // // Clear resets |foo| to its value when the PropertyAccessor was created. // accessors["foo"]->Clear(); // foo == true // // Generic accessors that provide write capability will check that the // new value differs from the present one. If the old and new values // are the same, the setter will not invoke the assignment operator, and // will return false. // // Custom accessors are responsible for handling set-to-same-value // themselves. It is not possible to handle that here, because some // custom getters return default values, rather than the actual // value. (I'm looking at you, WiFi::GetBgscanMethod.) template class PropertyAccessor : public AccessorInterface { public: explicit PropertyAccessor(T* property) : property_(property), default_value_(*property) { DCHECK(property); } ~PropertyAccessor() override {} void Clear(Error* error) override { Set(default_value_, error); } T Get(Error* /*error*/) override { return *property_; } bool Set(const T& value, Error* /*error*/) override { if (*property_ == value) { return false; } *property_ = value; return true; } private: T* const property_; const T default_value_; DISALLOW_COPY_AND_ASSIGN(PropertyAccessor); }; template class ConstPropertyAccessor : public AccessorInterface { public: explicit ConstPropertyAccessor(const T* property) : property_(property) { DCHECK(property); } ~ConstPropertyAccessor() override {} void Clear(Error* error) override { // TODO(quiche): check if this is the right error. // (maybe Error::kInvalidProperty instead?) error->Populate(Error::kInvalidArguments, "Property is read-only"); } T Get(Error* /*error*/) override { return *property_; } bool Set(const T& /*value*/, Error* error) override { // TODO(quiche): check if this is the right error. // (maybe Error::kPermissionDenied instead?) error->Populate(Error::kInvalidArguments, "Property is read-only"); return false; } private: const T* const property_; DISALLOW_COPY_AND_ASSIGN(ConstPropertyAccessor); }; template class WriteOnlyPropertyAccessor : public AccessorInterface { public: explicit WriteOnlyPropertyAccessor(T* property) : property_(property), default_value_(*property) { DCHECK(property); } ~WriteOnlyPropertyAccessor() override {} void Clear(Error* error) override { Set(default_value_, error); } T Get(Error* error) override { error->Populate(Error::kPermissionDenied, "Property is write-only"); return T(); } bool Set(const T& value, Error* /*error*/) override { if (*property_ == value) { return false; } *property_ = value; return true; } private: FRIEND_TEST(PropertyAccessorTest, SignedIntCorrectness); FRIEND_TEST(PropertyAccessorTest, UnsignedIntCorrectness); FRIEND_TEST(PropertyAccessorTest, StringCorrectness); FRIEND_TEST(PropertyAccessorTest, ByteArrayCorrectness); T* const property_; const T default_value_; DISALLOW_COPY_AND_ASSIGN(WriteOnlyPropertyAccessor); }; // CustomAccessor<> allows custom getter and setter methods to be provided. // Thus, if the state to be returned is to be derived on-demand, or if // setting the property requires validation, we can still fit it into the // AccessorInterface<> framework. // // If the property is write-only, use CustomWriteOnlyAccessor instead. template class CustomAccessor : public AccessorInterface { public: // |target| is the object on which to call the methods |getter|, |setter| // and |clearer|. |setter| is allowed to be NULL, in which case we will // simply reject attempts to set via the accessor. |setter| should return // true if the value was changed, and false otherwise. |clearer| is allowed // to be NULL (which is what happens if it is not passed to the constructor), // in which case, |setter| is called is called with the default value. // It is an error to pass NULL for either |target| or |getter|. CustomAccessor(C* target, T(C::*getter)(Error* error), bool(C::*setter)(const T& value, Error* error), void(C::*clearer)(Error* error)) : target_(target), default_value_(), getter_(getter), setter_(setter), clearer_(clearer) { DCHECK(target); DCHECK(getter); // otherwise, use CustomWriteOnlyAccessor if (setter_) { Error e; default_value_ = Get(&e); } } CustomAccessor(C* target, T(C::*getter)(Error* error), bool(C::*setter)(const T& value, Error* error)) : CustomAccessor(target, getter, setter, nullptr) {} ~CustomAccessor() override {} void Clear(Error* error) override { if (clearer_) { (target_->*clearer_)(error); } else { Set(default_value_, error); } } T Get(Error* error) override { return (target_->*getter_)(error); } bool Set(const T& value, Error* error) override { if (setter_) { return (target_->*setter_)(value, error); } else { error->Populate(Error::kInvalidArguments, "Property is read-only"); return false; } } private: C* const target_; // |default_value_| is non-const because it can't be initialized in // the initializer list. T default_value_; T(C::*const getter_)(Error* error); bool(C::*const setter_)(const T& value, Error* error); // NOLINT - "casting" void(C::*const clearer_)(Error* error); DISALLOW_COPY_AND_ASSIGN(CustomAccessor); }; // CustomWriteOnlyAccessor<> allows a custom writer method to be provided. // Get returns an error automatically. Clear resets the value to a // default value. template class CustomWriteOnlyAccessor : public AccessorInterface { public: // |target| is the object on which to call |setter| and |clearer|. // // |target| and |setter| must be non-NULL. |setter| should return true // if the value was changed, and false otherwise. // // Either |clearer| or |default_value|, but not both, must be non-NULL. // Whichever is non-NULL is used to clear the property. CustomWriteOnlyAccessor(C* target, bool(C::*setter)(const T& value, Error* error), void(C::*clearer)(Error* error), const T* default_value) : target_(target), setter_(setter), clearer_(clearer), default_value_() { DCHECK(target); DCHECK(setter); DCHECK(clearer || default_value); DCHECK(!clearer || !default_value); if (default_value) { default_value_ = *default_value; } } ~CustomWriteOnlyAccessor() override {} void Clear(Error* error) override { if (clearer_) { (target_->*clearer_)(error); } else { Set(default_value_, error); } } T Get(Error* error) override { error->Populate(Error::kPermissionDenied, "Property is write-only"); return T(); } bool Set(const T& value, Error* error) override { return (target_->*setter_)(value, error); } private: C* const target_; bool(C::*const setter_)(const T& value, Error* error); // NOLINT - "casting" void(C::*const clearer_)(Error* error); // |default_value_| is non-const because it can't be initialized in // the initializer list. T default_value_; DISALLOW_COPY_AND_ASSIGN(CustomWriteOnlyAccessor); }; // CustomReadOnlyAccessor<> allows a custom getter method to be provided. // Set and Clear return errors automatically. template class CustomReadOnlyAccessor : public AccessorInterface { public: // |target| is the object on which to call the |getter| method. // |getter| is a const method. If a non-const method needs to be used, // use the CustomAccessor with a NULL setter instead. CustomReadOnlyAccessor(C* target, T(C::*getter)(Error* error) const) : target_(target), getter_(getter) { DCHECK(target); DCHECK(getter); } ~CustomReadOnlyAccessor() override {} void Clear(Error* error) override { error->Populate(Error::kInvalidArguments, "Property is read-only"); } T Get(Error* error) override { return (target_->*getter_)(error); } bool Set(const T& value, Error* error) override { error->Populate(Error::kInvalidArguments, "Property is read-only"); return false; } private: C* const target_; T(C::*const getter_)(Error* error) const; DISALLOW_COPY_AND_ASSIGN(CustomReadOnlyAccessor); }; // CustomMappedAccessor<> passes an argument to the getter and setter // so that a generic method can be used, for example one that accesses the // property in a map. template class CustomMappedAccessor : public AccessorInterface { public: // |target| is the object on which to call the methods |getter| and |setter|. // |setter| is allowed to be NULL, in which case we will simply reject // attempts to set via the accessor. |setter| should return true if the // value was changed, and false otherwise. // |argument| is passed to the getter and setter methods to disambiguate // between different properties in |target|. // It is an error to pass NULL for any of |target|, |clearer| or |getter|. CustomMappedAccessor(C* target, void(C::*clearer)(const A& argument, Error* error), T(C::*getter)(const A& argument, Error* error), bool(C::*setter)(const A& argument, const T& value, Error* error), const A& argument) : target_(target), clearer_(clearer), getter_(getter), setter_(setter), argument_(argument) { DCHECK(clearer); DCHECK(target); DCHECK(getter); } ~CustomMappedAccessor() override {} void Clear(Error* error) override { (target_->*clearer_)(argument_, error); } T Get(Error* error) override { return (target_->*getter_)(argument_, error); } bool Set(const T& value, Error* error) override { if (setter_) { return (target_->*setter_)(argument_, value, error); } else { error->Populate(Error::kInvalidArguments, "Property is read-only"); return false; } } private: C* const target_; void(C::*const clearer_)(const A& argument, Error* error); T(C::*const getter_)(const A& argument, Error* error); bool(C::*const setter_)(const A& argument, // NOLINT - "casting" const T& value, Error* error); A argument_; DISALLOW_COPY_AND_ASSIGN(CustomMappedAccessor); }; } // namespace shill #endif // SHILL_PROPERTY_ACCESSOR_H_