1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef DBUS_PROPERTY_H_ 6 #define DBUS_PROPERTY_H_ 7 8 #include <stdint.h> 9 10 #include <map> 11 #include <string> 12 #include <unordered_map> 13 #include <utility> 14 #include <vector> 15 16 #include "base/bind.h" 17 #include "base/callback.h" 18 #include "base/macros.h" 19 #include "dbus/dbus_export.h" 20 #include "dbus/message.h" 21 #include "dbus/object_proxy.h" 22 23 // D-Bus objects frequently provide sets of properties accessed via a 24 // standard interface of method calls and signals to obtain the current value, 25 // set a new value and be notified of changes to the value. Unfortunately this 26 // interface makes heavy use of variants and dictionaries of variants. The 27 // classes defined here make dealing with properties in a type-safe manner 28 // possible. 29 // 30 // Client implementation classes should define a Properties structure, deriving 31 // from the PropertySet class defined here. This structure should contain a 32 // member for each property defined as an instance of the Property<> class, 33 // specifying the type to the template. Finally the structure should chain up 34 // to the PropertySet constructor, and then call RegisterProperty() for each 35 // property defined to associate them with their string name. 36 // 37 // Example: 38 // class ExampleClient { 39 // public: 40 // struct Properties : public dbus::PropertySet { 41 // dbus::Property<std::string> name; 42 // dbus::Property<uint16_t> version; 43 // dbus::Property<dbus::ObjectPath> parent; 44 // dbus::Property<std::vector<std::string> > children; 45 // 46 // Properties(dbus::ObjectProxy* object_proxy, 47 // const PropertyChangedCallback callback) 48 // : dbus::PropertySet(object_proxy, "com.example.DBus", callback) { 49 // RegisterProperty("Name", &name); 50 // RegisterProperty("Version", &version); 51 // RegisterProperty("Parent", &parent); 52 // RegisterProperty("Children", &children); 53 // } 54 // virtual ~Properties() {} 55 // }; 56 // 57 // The Properties structure requires a pointer to the object proxy of the 58 // actual object to track, and after construction should have signals 59 // connected to that object and initial values set by calling ConnectSignals() 60 // and GetAll(). The structure should not outlive the object proxy, so it 61 // is recommended that the lifecycle of both be managed together. 62 // 63 // Example (continued): 64 // 65 // typedef std::map<std::pair<dbus::ObjectProxy*, Properties*> > Object; 66 // typedef std::map<dbus::ObjectPath, Object> ObjectMap; 67 // ObjectMap object_map_; 68 // 69 // dbus::ObjectProxy* GetObjectProxy(const dbus::ObjectPath& object_path) { 70 // return GetObject(object_path).first; 71 // } 72 // 73 // Properties* GetProperties(const dbus::ObjectPath& object_path) { 74 // return GetObject(object_path).second; 75 // } 76 // 77 // Object GetObject(const dbus::ObjectPath& object_path) { 78 // ObjectMap::iterator it = object_map_.find(object_path); 79 // if (it != object_map_.end()) 80 // return it->second; 81 // 82 // dbus::ObjectProxy* object_proxy = bus->GetObjectProxy(...); 83 // // connect signals, etc. 84 // 85 // Properties* properties = new Properties( 86 // object_proxy, 87 // base::Bind(&PropertyChanged, 88 // weak_ptr_factory_.GetWeakPtr(), 89 // object_path)); 90 // properties->ConnectSignals(); 91 // properties->GetAll(); 92 // 93 // Object object = std::make_pair(object_proxy, properties); 94 // object_map_[object_path] = object; 95 // return object; 96 // } 97 // }; 98 // 99 // This now allows code using the client implementation to access properties 100 // in a type-safe manner, and assuming the PropertyChanged callback is 101 // propogated up to observers, be notified of changes. A typical access of 102 // the current value of the name property would be: 103 // 104 // ExampleClient::Properties* p = example_client->GetProperties(object_path); 105 // std::string name = p->name.value(); 106 // 107 // Normally these values are updated from signals emitted by the remote object, 108 // in case an explicit round-trip is needed to obtain the current value, the 109 // Get() method can be used and indicates whether or not the value update was 110 // successful. The updated value can be obtained in the callback using the 111 // value() method. 112 // 113 // p->children.Get(base::Bind(&OnGetChildren)); 114 // 115 // A new value can be set using the Set() method, the callback indicates 116 // success only; it is up to the remote object when (and indeed if) it updates 117 // the property value, and whether it emits a signal or a Get() call is 118 // required to obtain it. 119 // 120 // p->version.Set(20, base::Bind(&OnSetVersion)) 121 122 namespace dbus { 123 124 // D-Bus Properties interface constants, declared here rather than 125 // in property.cc because template methods use them. 126 const char kPropertiesInterface[] = "org.freedesktop.DBus.Properties"; 127 const char kPropertiesGetAll[] = "GetAll"; 128 const char kPropertiesGet[] = "Get"; 129 const char kPropertiesSet[] = "Set"; 130 const char kPropertiesChanged[] = "PropertiesChanged"; 131 132 class PropertySet; 133 134 // PropertyBase is an abstract base-class consisting of the parts of 135 // the Property<> template that are not type-specific, such as the 136 // associated PropertySet, property name, and the type-unsafe parts 137 // used by PropertySet. 138 class CHROME_DBUS_EXPORT PropertyBase { 139 public: 140 PropertyBase(); 141 virtual ~PropertyBase(); 142 143 // Initializes the |property_set| and property |name| so that method 144 // calls may be made from this class. This method is called by 145 // PropertySet::RegisterProperty() passing |this| for |property_set| so 146 // there should be no need to call it directly. If you do beware that 147 // no ownership or reference to |property_set| is taken so that object 148 // must outlive this one. 149 void Init(PropertySet* property_set, const std::string& name); 150 151 // Retrieves the name of this property, this may be useful in observers 152 // to avoid specifying the name in more than once place, e.g. 153 // 154 // void Client::PropertyChanged(const dbus::ObjectPath& object_path, 155 // const std::string &property_name) { 156 // Properties& properties = GetProperties(object_path); 157 // if (property_name == properties.version.name()) { 158 // // Handle version property changing 159 // } 160 // } 161 const std::string& name() const { return name_; } 162 163 // Returns true if property is valid, false otherwise. 164 bool is_valid() const { return is_valid_; } 165 166 // Allows to mark Property as valid or invalid. 167 void set_valid(bool is_valid) { is_valid_ = is_valid; } 168 169 // Method used by PropertySet to retrieve the value from a MessageReader, 170 // no knowledge of the contained type is required, this method returns 171 // true if its expected type was found, false if not. 172 // Implementation provided by specialization. 173 virtual bool PopValueFromReader(MessageReader* reader) = 0; 174 175 // Method used by PropertySet to append the set value to a MessageWriter, 176 // no knowledge of the contained type is required. 177 // Implementation provided by specialization. 178 virtual void AppendSetValueToWriter(MessageWriter* writer) = 0; 179 180 // Method used by test and stub implementations of dbus::PropertySet::Set 181 // to replace the property value with the set value without using a 182 // dbus::MessageReader. 183 virtual void ReplaceValueWithSetValue() = 0; 184 185 protected: 186 // Retrieves the associated property set. 187 PropertySet* property_set() { return property_set_; } 188 189 private: 190 // Pointer to the PropertySet instance that this instance is a member of, 191 // no ownership is taken and |property_set_| must outlive this class. 192 PropertySet* property_set_; 193 194 bool is_valid_; 195 196 // Name of the property. 197 std::string name_; 198 199 DISALLOW_COPY_AND_ASSIGN(PropertyBase); 200 }; 201 202 // PropertySet groups a collection of properties for a remote object 203 // together into a single structure, fixing their types and name such 204 // that calls made through it are type-safe. 205 // 206 // Clients always sub-class this to add the properties, and should always 207 // provide a constructor that chains up to this and then calls 208 // RegisterProperty() for each property defined. 209 // 210 // After creation, client code should call ConnectSignals() and most likely 211 // GetAll() to seed initial values and update as changes occur. 212 class CHROME_DBUS_EXPORT PropertySet { 213 public: 214 // Callback for changes to cached values of properties, either notified 215 // via signal, or as a result of calls to Get() and GetAll(). The |name| 216 // argument specifies the name of the property changed. 217 typedef base::Callback<void(const std::string& name)> PropertyChangedCallback; 218 219 // Constructs a property set, where |object_proxy| specifies the proxy for 220 // the/ remote object that these properties are for, care should be taken to 221 // ensure that this object does not outlive the lifetime of the proxy; 222 // |interface| specifies the D-Bus interface of these properties, and 223 // |property_changed_callback| specifies the callback for when properties 224 // are changed, this may be a NULL callback. 225 PropertySet(ObjectProxy* object_proxy, const std::string& interface, 226 const PropertyChangedCallback& property_changed_callback); 227 228 // Destructor; we don't hold on to any references or memory that needs 229 // explicit clean-up, but clang thinks we might. 230 virtual ~PropertySet(); 231 232 // Registers a property, generally called from the subclass constructor; 233 // pass the |name| of the property as used in method calls and signals, 234 // and the pointer to the |property| member of the structure. This will 235 // call the PropertyBase::Init method. 236 void RegisterProperty(const std::string& name, PropertyBase* property); 237 238 // Connects property change notification signals to the object, generally 239 // called immediately after the object is created and before calls to other 240 // methods. Sub-classes may override to use different D-Bus signals. 241 virtual void ConnectSignals(); 242 243 // Methods connected by ConnectSignals() and called by dbus:: when 244 // a property is changed. Sub-classes may override if the property 245 // changed signal provides different arguments. 246 virtual void ChangedReceived(Signal* signal); 247 virtual void ChangedConnected(const std::string& interface_name, 248 const std::string& signal_name, 249 bool success); 250 251 // Callback for Get() method, |success| indicates whether or not the 252 // value could be retrived, if true the new value can be obtained by 253 // calling value() on the property. 254 typedef base::Callback<void(bool success)> GetCallback; 255 256 // Requests an updated value from the remote object for |property| 257 // incurring a round-trip. |callback| will be called when the new 258 // value is available. This may not be implemented by some interfaces, 259 // and may be overriden by sub-classes if interfaces use different 260 // method calls. 261 virtual void Get(PropertyBase* property, GetCallback callback); 262 virtual void OnGet(PropertyBase* property, GetCallback callback, 263 Response* response); 264 265 // The synchronous version of Get(). 266 // This should never be used on an interactive thread. 267 virtual bool GetAndBlock(PropertyBase* property); 268 269 // Queries the remote object for values of all properties and updates 270 // initial values. Sub-classes may override to use a different D-Bus 271 // method, or if the remote object does not support retrieving all 272 // properties, either ignore or obtain each property value individually. 273 virtual void GetAll(); 274 virtual void OnGetAll(Response* response); 275 276 // Callback for Set() method, |success| indicates whether or not the 277 // new property value was accepted by the remote object. 278 typedef base::Callback<void(bool success)> SetCallback; 279 280 // Requests that the remote object for |property| change the property to 281 // its new value. |callback| will be called to indicate the success or 282 // failure of the request, however the new value may not be available 283 // depending on the remote object. This method may be overridden by 284 // sub-classes if interfaces use different method calls. 285 virtual void Set(PropertyBase* property, SetCallback callback); 286 virtual void OnSet(PropertyBase* property, SetCallback callback, 287 Response* response); 288 289 // The synchronous version of Set(). 290 // This should never be used on an interactive thread. 291 virtual bool SetAndBlock(PropertyBase* property); 292 293 // Update properties by reading an array of dictionary entries, each 294 // containing a string with the name and a variant with the value, from 295 // |message_reader|. Returns false if message is in incorrect format. 296 bool UpdatePropertiesFromReader(MessageReader* reader); 297 298 // Updates a single property by reading a string with the name and a 299 // variant with the value from |message_reader|. Returns false if message 300 // is in incorrect format, or property type doesn't match. 301 bool UpdatePropertyFromReader(MessageReader* reader); 302 303 // Calls the property changed callback passed to the constructor, used 304 // by sub-classes that do not call UpdatePropertiesFromReader() or 305 // UpdatePropertyFromReader(). Takes the |name| of the changed property. 306 void NotifyPropertyChanged(const std::string& name); 307 308 // Retrieves the object proxy this property set was initialized with, 309 // provided for sub-classes overriding methods that make D-Bus calls 310 // and for Property<>. Not permitted with const references to this class. 311 ObjectProxy* object_proxy() { return object_proxy_; } 312 313 // Retrieves the interface of this property set. 314 const std::string& interface() const { return interface_; } 315 316 protected: 317 // Get a weak pointer to this property set, provided so that sub-classes 318 // overriding methods that make D-Bus calls may use the existing (or 319 // override) callbacks without providing their own weak pointer factory. 320 base::WeakPtr<PropertySet> GetWeakPtr() { 321 return weak_ptr_factory_.GetWeakPtr(); 322 } 323 324 private: 325 // Invalidates properties by reading an array of names, from 326 // |message_reader|. Returns false if message is in incorrect format. 327 bool InvalidatePropertiesFromReader(MessageReader* reader); 328 329 // Pointer to object proxy for making method calls, no ownership is taken 330 // so this must outlive this class. 331 ObjectProxy* object_proxy_; 332 333 // Interface of property, e.g. "org.chromium.ExampleService", this is 334 // distinct from the interface of the method call itself which is the 335 // general D-Bus Properties interface "org.freedesktop.DBus.Properties". 336 std::string interface_; 337 338 // Callback for property changes. 339 PropertyChangedCallback property_changed_callback_; 340 341 // Map of properties (as PropertyBase*) defined in the structure to 342 // names as used in D-Bus method calls and signals. The base pointer 343 // restricts property access via this map to type-unsafe and non-specific 344 // actions only. 345 typedef std::map<const std::string, PropertyBase*> PropertiesMap; 346 PropertiesMap properties_map_; 347 348 // Weak pointer factory as D-Bus callbacks may last longer than these 349 // objects. 350 base::WeakPtrFactory<PropertySet> weak_ptr_factory_; 351 352 DISALLOW_COPY_AND_ASSIGN(PropertySet); 353 }; 354 355 // Property template, this defines the type-specific and type-safe methods 356 // of properties that can be accessed as members of a PropertySet structure. 357 // 358 // Properties provide a cached value that has an initial sensible default 359 // until the reply to PropertySet::GetAll() is retrieved and is updated by 360 // all calls to that method, PropertySet::Get() and property changed signals 361 // also handled by PropertySet. It can be obtained by calling value() on the 362 // property. 363 // 364 // It is recommended that this cached value be used where necessary, with 365 // code using PropertySet::PropertyChangedCallback to be notified of changes, 366 // rather than incurring a round-trip to the remote object for each property 367 // access. 368 // 369 // Where a round-trip is necessary, the Get() method is provided. And to 370 // update the remote object value, the Set() method is also provided; these 371 // both simply call methods on PropertySet. 372 // 373 // Handling of particular D-Bus types is performed via specialization, 374 // typically the PopValueFromReader() and AppendSetValueToWriter() methods 375 // will need to be provided, and in rare cases a constructor to provide a 376 // default value. Specializations for basic D-Bus types, strings, object 377 // paths and arrays are provided for you. 378 template <class T> 379 class CHROME_DBUS_EXPORT Property : public PropertyBase { 380 public: 381 Property() {} 382 ~Property() override {} 383 384 // Retrieves the cached value. 385 const T& value() const { return value_; } 386 387 // Requests an updated value from the remote object incurring a 388 // round-trip. |callback| will be called when the new value is available. 389 // This may not be implemented by some interfaces. 390 virtual void Get(dbus::PropertySet::GetCallback callback) { 391 property_set()->Get(this, callback); 392 } 393 394 // The synchronous version of Get(). 395 // This should never be used on an interactive thread. 396 virtual bool GetAndBlock() { 397 return property_set()->GetAndBlock(this); 398 } 399 400 // Requests that the remote object change the property value to |value|, 401 // |callback| will be called to indicate the success or failure of the 402 // request, however the new value may not be available depending on the 403 // remote object. 404 virtual void Set(const T& value, dbus::PropertySet::SetCallback callback) { 405 set_value_ = value; 406 property_set()->Set(this, callback); 407 } 408 409 // The synchronous version of Set(). 410 // This should never be used on an interactive thread. 411 virtual bool SetAndBlock(const T& value) { 412 set_value_ = value; 413 return property_set()->SetAndBlock(this); 414 } 415 416 // Method used by PropertySet to retrieve the value from a MessageReader, 417 // no knowledge of the contained type is required, this method returns 418 // true if its expected type was found, false if not. 419 bool PopValueFromReader(MessageReader* reader) override; 420 421 // Method used by PropertySet to append the set value to a MessageWriter, 422 // no knowledge of the contained type is required. 423 // Implementation provided by specialization. 424 void AppendSetValueToWriter(MessageWriter* writer) override; 425 426 // Method used by test and stub implementations of dbus::PropertySet::Set 427 // to replace the property value with the set value without using a 428 // dbus::MessageReader. 429 void ReplaceValueWithSetValue() override { 430 value_ = set_value_; 431 property_set()->NotifyPropertyChanged(name()); 432 } 433 434 // Method used by test and stub implementations to directly set the 435 // value of a property. 436 void ReplaceValue(const T& value) { 437 value_ = value; 438 property_set()->NotifyPropertyChanged(name()); 439 } 440 441 // Method used by test and stub implementations to directly set the 442 // |set_value_| of a property. 443 void ReplaceSetValueForTesting(const T& value) { set_value_ = value; } 444 445 private: 446 // Current cached value of the property. 447 T value_; 448 449 // Replacement value of the property. 450 T set_value_; 451 }; 452 453 // Clang and GCC don't agree on how attributes should work for explicitly 454 // instantiated templates. GCC ignores attributes on explicit instantiations 455 // (and emits a warning) while Clang requires the visiblity attribute on the 456 // explicit instantiations for them to be visible to other compilation units. 457 // Hopefully clang and GCC agree one day, and this can be cleaned up: 458 // https://llvm.org/bugs/show_bug.cgi?id=24815 459 #pragma GCC diagnostic push 460 #pragma GCC diagnostic ignored "-Wattributes" 461 462 template <> 463 CHROME_DBUS_EXPORT Property<uint8_t>::Property(); 464 template <> 465 CHROME_DBUS_EXPORT bool Property<uint8_t>::PopValueFromReader( 466 MessageReader* reader); 467 template <> 468 CHROME_DBUS_EXPORT void Property<uint8_t>::AppendSetValueToWriter( 469 MessageWriter* writer); 470 extern template class CHROME_DBUS_EXPORT Property<uint8_t>; 471 472 template <> 473 CHROME_DBUS_EXPORT Property<bool>::Property(); 474 template <> 475 CHROME_DBUS_EXPORT bool Property<bool>::PopValueFromReader( 476 MessageReader* reader); 477 template <> 478 CHROME_DBUS_EXPORT void Property<bool>::AppendSetValueToWriter( 479 MessageWriter* writer); 480 extern template class CHROME_DBUS_EXPORT Property<bool>; 481 482 template <> 483 CHROME_DBUS_EXPORT Property<int16_t>::Property(); 484 template <> 485 CHROME_DBUS_EXPORT bool Property<int16_t>::PopValueFromReader( 486 MessageReader* reader); 487 template <> 488 CHROME_DBUS_EXPORT void Property<int16_t>::AppendSetValueToWriter( 489 MessageWriter* writer); 490 extern template class CHROME_DBUS_EXPORT Property<int16_t>; 491 492 template <> 493 CHROME_DBUS_EXPORT Property<uint16_t>::Property(); 494 template <> 495 CHROME_DBUS_EXPORT bool Property<uint16_t>::PopValueFromReader( 496 MessageReader* reader); 497 template <> 498 CHROME_DBUS_EXPORT void Property<uint16_t>::AppendSetValueToWriter( 499 MessageWriter* writer); 500 extern template class CHROME_DBUS_EXPORT Property<uint16_t>; 501 502 template <> 503 CHROME_DBUS_EXPORT Property<int32_t>::Property(); 504 template <> 505 CHROME_DBUS_EXPORT bool Property<int32_t>::PopValueFromReader( 506 MessageReader* reader); 507 template <> 508 CHROME_DBUS_EXPORT void Property<int32_t>::AppendSetValueToWriter( 509 MessageWriter* writer); 510 extern template class CHROME_DBUS_EXPORT Property<int32_t>; 511 512 template <> 513 CHROME_DBUS_EXPORT Property<uint32_t>::Property(); 514 template <> 515 CHROME_DBUS_EXPORT bool Property<uint32_t>::PopValueFromReader( 516 MessageReader* reader); 517 template <> 518 CHROME_DBUS_EXPORT void Property<uint32_t>::AppendSetValueToWriter( 519 MessageWriter* writer); 520 extern template class CHROME_DBUS_EXPORT Property<uint32_t>; 521 522 template <> 523 CHROME_DBUS_EXPORT Property<int64_t>::Property(); 524 template <> 525 CHROME_DBUS_EXPORT bool Property<int64_t>::PopValueFromReader( 526 MessageReader* reader); 527 template <> 528 CHROME_DBUS_EXPORT void Property<int64_t>::AppendSetValueToWriter( 529 MessageWriter* writer); 530 extern template class CHROME_DBUS_EXPORT Property<int64_t>; 531 532 template <> 533 CHROME_DBUS_EXPORT Property<uint64_t>::Property(); 534 template <> 535 CHROME_DBUS_EXPORT bool Property<uint64_t>::PopValueFromReader( 536 MessageReader* reader); 537 template <> 538 CHROME_DBUS_EXPORT void Property<uint64_t>::AppendSetValueToWriter( 539 MessageWriter* writer); 540 extern template class CHROME_DBUS_EXPORT Property<uint64_t>; 541 542 template <> 543 CHROME_DBUS_EXPORT Property<double>::Property(); 544 template <> 545 CHROME_DBUS_EXPORT bool Property<double>::PopValueFromReader( 546 MessageReader* reader); 547 template <> 548 CHROME_DBUS_EXPORT void Property<double>::AppendSetValueToWriter( 549 MessageWriter* writer); 550 extern template class CHROME_DBUS_EXPORT Property<double>; 551 552 template <> 553 CHROME_DBUS_EXPORT bool Property<std::string>::PopValueFromReader( 554 MessageReader* reader); 555 template <> 556 CHROME_DBUS_EXPORT void Property<std::string>::AppendSetValueToWriter( 557 MessageWriter* writer); 558 extern template class CHROME_DBUS_EXPORT Property<std::string>; 559 560 template <> 561 CHROME_DBUS_EXPORT bool Property<ObjectPath>::PopValueFromReader( 562 MessageReader* reader); 563 template <> 564 CHROME_DBUS_EXPORT void Property<ObjectPath>::AppendSetValueToWriter( 565 MessageWriter* writer); 566 extern template class CHROME_DBUS_EXPORT Property<ObjectPath>; 567 568 template <> 569 CHROME_DBUS_EXPORT bool Property<std::vector<std::string>>::PopValueFromReader( 570 MessageReader* reader); 571 template <> 572 CHROME_DBUS_EXPORT void Property< 573 std::vector<std::string>>::AppendSetValueToWriter(MessageWriter* writer); 574 extern template class CHROME_DBUS_EXPORT Property<std::vector<std::string>>; 575 576 template <> 577 CHROME_DBUS_EXPORT bool Property<std::vector<ObjectPath>>::PopValueFromReader( 578 MessageReader* reader); 579 template <> 580 CHROME_DBUS_EXPORT void Property< 581 std::vector<ObjectPath>>::AppendSetValueToWriter(MessageWriter* writer); 582 extern template class CHROME_DBUS_EXPORT Property<std::vector<ObjectPath>>; 583 584 template <> 585 CHROME_DBUS_EXPORT bool Property<std::vector<uint8_t>>::PopValueFromReader( 586 MessageReader* reader); 587 template <> 588 CHROME_DBUS_EXPORT void Property<std::vector<uint8_t>>::AppendSetValueToWriter( 589 MessageWriter* writer); 590 extern template class CHROME_DBUS_EXPORT Property<std::vector<uint8_t>>; 591 592 template <> 593 CHROME_DBUS_EXPORT bool 594 Property<std::map<std::string, std::string>>::PopValueFromReader( 595 MessageReader* reader); 596 template <> 597 CHROME_DBUS_EXPORT void 598 Property<std::map<std::string, std::string>>::AppendSetValueToWriter( 599 MessageWriter* writer); 600 extern template class CHROME_DBUS_EXPORT 601 Property<std::map<std::string, std::string>>; 602 603 template <> 604 CHROME_DBUS_EXPORT bool 605 Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>:: 606 PopValueFromReader(MessageReader* reader); 607 template <> 608 CHROME_DBUS_EXPORT void 609 Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>:: 610 AppendSetValueToWriter(MessageWriter* writer); 611 extern template class CHROME_DBUS_EXPORT 612 Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>; 613 614 template <> 615 CHROME_DBUS_EXPORT bool 616 Property<std::unordered_map<std::string, std::vector<uint8_t>>>:: 617 PopValueFromReader(MessageReader* reader); 618 template <> 619 CHROME_DBUS_EXPORT void 620 Property<std::unordered_map<std::string, std::vector<uint8_t>>>:: 621 AppendSetValueToWriter(MessageWriter* writer); 622 extern template class CHROME_DBUS_EXPORT 623 Property<std::unordered_map<std::string, std::vector<uint8_t>>>; 624 625 template <> 626 CHROME_DBUS_EXPORT bool 627 Property<std::unordered_map<uint16_t, std::vector<uint8_t>>>:: 628 PopValueFromReader(MessageReader* reader); 629 template <> 630 CHROME_DBUS_EXPORT void 631 Property<std::unordered_map<uint16_t, std::vector<uint8_t>>>:: 632 AppendSetValueToWriter(MessageWriter* writer); 633 extern template class CHROME_DBUS_EXPORT 634 Property<std::unordered_map<uint16_t, std::vector<uint8_t>>>; 635 636 #pragma GCC diagnostic pop 637 638 } // namespace dbus 639 640 #endif // DBUS_PROPERTY_H_ 641