/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_mscom_COMPtrHolder_h #define mozilla_mscom_COMPtrHolder_h #include "mozilla/Attributes.h" #include "mozilla/Move.h" #include "mozilla/mscom/ProxyStream.h" #include "mozilla/mscom/Ptr.h" namespace mozilla { namespace mscom { template<typename Interface, const IID& _IID> class COMPtrHolder { public: typedef ProxyUniquePtr<Interface> COMPtrType; typedef COMPtrHolder<Interface, _IID> ThisType; COMPtrHolder() {} MOZ_IMPLICIT COMPtrHolder(decltype(nullptr)) { } explicit COMPtrHolder(COMPtrType&& aPtr) : mPtr(Forward<COMPtrType>(aPtr)) { } Interface* Get() const { return mPtr.get(); } MOZ_MUST_USE Interface* Release() { return mPtr.release(); } void Set(COMPtrType&& aPtr) { mPtr = Forward<COMPtrType>(aPtr); } COMPtrHolder(const COMPtrHolder& aOther) = delete; COMPtrHolder(COMPtrHolder&& aOther) : mPtr(Move(aOther.mPtr)) { } // COMPtrHolder is eventually added as a member of a struct that is declared // in IPDL. The generated C++ code for that IPDL struct includes copy // constructors and assignment operators that assume that all members are // copyable. I don't think that those copy constructors and operator= are // actually used by any generated code, but they are made available. Since no // move semantics are available, this terrible hack makes COMPtrHolder build // when used as a member of an IPDL struct. ThisType& operator=(const ThisType& aOther) { Set(Move(aOther.mPtr)); return *this; } ThisType& operator=(ThisType&& aOther) { Set(Move(aOther.mPtr)); return *this; } bool operator==(const ThisType& aOther) const { return mPtr == aOther.mPtr; } bool IsNull() const { return !mPtr; } private: // This is mutable to facilitate the above operator= hack mutable COMPtrType mPtr; }; } // namespace mscom } // namespace mozilla namespace IPC { template<typename Interface, const IID& _IID> struct ParamTraits<mozilla::mscom::COMPtrHolder<Interface, _IID>> { typedef mozilla::mscom::COMPtrHolder<Interface, _IID> paramType; static void Write(Message* aMsg, const paramType& aParam) { mozilla::mscom::ProxyStream proxyStream(_IID, aParam.Get()); int bufLen; const BYTE* buf = proxyStream.GetBuffer(bufLen); MOZ_ASSERT(buf || !bufLen); aMsg->WriteInt(bufLen); aMsg->WriteBytes(reinterpret_cast<const char*>(buf), bufLen); } static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) { int length; if (!aMsg->ReadLength(aIter, &length)) { return false; } mozilla::UniquePtr<BYTE[]> buf; if (length) { buf = mozilla::MakeUnique<BYTE[]>(length); if (!aMsg->ReadBytesInto(aIter, buf.get(), length)) { return false; } } mozilla::mscom::ProxyStream proxyStream(buf.get(), length); if (!proxyStream.IsValid()) { return false; } Interface* rawInterface = nullptr; if (!proxyStream.GetInterface(_IID, (void**)&rawInterface)) { return false; } typename paramType::COMPtrType ptr(rawInterface); aResult->Set(mozilla::Move(ptr)); return true; } }; } // namespace IPC #endif // mozilla_mscom_COMPtrHolder_h