1 // Copyright 2019 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 IOS_CHROME_BROWSER_MAIN_BROWSER_USER_DATA_H_
6 #define IOS_CHROME_BROWSER_MAIN_BROWSER_USER_DATA_H_
7 
8 #include "base/memory/ptr_util.h"
9 #include "base/supports_user_data.h"
10 #import "ios/chrome/browser/main/browser.h"
11 
12 // This macro declares a static variable inside the class that inherits from
13 // BrwoserUserData. The address of this static variable is used as the key to
14 // store/retrieve an instance of the class on/from a Browser.
15 #define BROWSER_USER_DATA_KEY_DECL() static constexpr int kUserDataKey = 0
16 
17 // This macro instantiates the static variable declared by the previous macro.
18 // It must live in a .mm/.cc file to ensure that there is only one instantiation
19 // of the static variable.
20 #define BROWSER_USER_DATA_KEY_IMPL(Type) const int Type::kUserDataKey;
21 
22 // A base class for classes attached to, and scoped to, the lifetime of a
23 // Browser. For example:
24 //
25 // --- in foo_browser_agent.h ---
26 // class FooBrowserAgent : public BrowserUserData<FooBrowserAgent> {
27 //  public:
28 //   ~FooBrowserAgent() override;
29 //   // ... more public stuff here ...
30 //  private:
31 //   explicit FooBrowserAgent(Browser* browser);
32 //   friend class BrowserUserData<FooBrowserAgent>;
33 //   BROWSER_USER_DATA_KEY_DECL();
34 //   // ... more private stuff here ...
35 // };
36 //
37 // --- in foo_browser_agent.cc ---
38 // BROWSER_USER_DATA_KEY_IMPL(FooBrowserAgent)
39 template <typename T>
40 class BrowserUserData : public base::SupportsUserData::Data {
41  public:
42   // Creates an object of type T, and attaches it to the specified Browser.
43   // If an instance is already attached, does nothing.
CreateForBrowser(Browser * browser)44   static void CreateForBrowser(Browser* browser) {
45     if (!FromBrowser(browser))
46       browser->SetUserData(UserDataKey(), base::WrapUnique(new T(browser)));
47   }
48 
49   // Retrieves the instance of type T that was attached to the specified
50   // Browser (via CreateForBrowser above) and returns it. If no instance
51   // of the type was attached, returns nullptr.
FromBrowser(Browser * browser)52   static T* FromBrowser(Browser* browser) {
53     return static_cast<T*>(browser->GetUserData(UserDataKey()));
54   }
FromBrowser(const Browser * browser)55   static const T* FromBrowser(const Browser* browser) {
56     return static_cast<const T*>(browser->GetUserData(UserDataKey()));
57   }
58 
59   // Removes the instance attached to the specified Browser.
RemoveFromBrowser(Browser * browser)60   static void RemoveFromBrowser(Browser* browser) {
61     browser->RemoveUserData(UserDataKey());
62   }
63 
UserDataKey()64   static const void* UserDataKey() { return &T::kUserDataKey; }
65 };
66 
67 #endif  // IOS_CHROME_BROWSER_MAIN_BROWSER_USER_DATA_H_
68