// Copyright Sebastian Jeckel 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef REACT_OBSERVER_H_INCLUDED
#define REACT_OBSERVER_H_INCLUDED
#pragma once
#include "react/detail/Defs.h"
#include
#include
#include "react/common/Util.h"
#include "react/detail/IReactiveNode.h"
#include "react/detail/ObserverBase.h"
#include "react/detail/graph/ObserverNodes.h"
/*****************************************/ REACT_BEGIN /*****************************************/
///////////////////////////////////////////////////////////////////////////////////////////////////
/// Forward declarations
///////////////////////////////////////////////////////////////////////////////////////////////////
template
class Signal;
template
class SignalPack;
template
class Events;
using REACT_IMPL::ObserverAction;
using REACT_IMPL::WeightHint;
///////////////////////////////////////////////////////////////////////////////////////////////////
/// Observer
///////////////////////////////////////////////////////////////////////////////////////////////////
template
class Observer
{
private:
using SubjectPtrT = std::shared_ptr;
using NodeT = REACT_IMPL::ObserverNode;
public:
// Default ctor
Observer() :
nodePtr_( nullptr ),
subjectPtr_( nullptr )
{}
// Move ctor
Observer(Observer&& other) :
nodePtr_( other.nodePtr_ ),
subjectPtr_( std::move(other.subjectPtr_) )
{
other.nodePtr_ = nullptr;
other.subjectPtr_.reset();
}
// Node ctor
Observer(NodeT* nodePtr, const SubjectPtrT& subjectPtr) :
nodePtr_( nodePtr ),
subjectPtr_( subjectPtr )
{}
// Move assignment
Observer& operator=(Observer&& other)
{
nodePtr_ = other.nodePtr_;
subjectPtr_ = std::move(other.subjectPtr_);
other.nodePtr_ = nullptr;
other.subjectPtr_.reset();
return *this;
}
// Deleted copy ctor and assignment
Observer(const Observer&) = delete;
Observer& operator=(const Observer&) = delete;
void Detach()
{
assert(IsValid());
subjectPtr_->UnregisterObserver(nodePtr_);
}
bool IsValid() const
{
return nodePtr_ != nullptr;
}
void SetWeightHint(WeightHint weight)
{
assert(IsValid());
nodePtr_->SetWeightHint(weight);
}
private:
// Owned by subject
NodeT* nodePtr_;
// While the observer handle exists, the subject is not destroyed
SubjectPtrT subjectPtr_;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
/// ScopedObserver
///////////////////////////////////////////////////////////////////////////////////////////////////
template
class ScopedObserver
{
public:
// Move ctor
ScopedObserver(ScopedObserver&& other) :
obs_( std::move(other.obs_) )
{}
// Construct from observer
ScopedObserver(Observer&& obs) :
obs_( std::move(obs) )
{}
// Move assignment
ScopedObserver& operator=(ScopedObserver&& other)
{
obs_ = std::move(other.obs_);
}
// Deleted default ctor, copy ctor and assignment
ScopedObserver() = delete;
ScopedObserver(const ScopedObserver&) = delete;
ScopedObserver& operator=(const ScopedObserver&) = delete;
~ScopedObserver()
{
obs_.Detach();
}
bool IsValid() const
{
return obs_.IsValid();
}
void SetWeightHint(WeightHint weight)
{
obs_.SetWeightHint(weight);
}
private:
Observer obs_;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
/// Observe - Signals
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
typename D,
typename FIn,
typename S
>
auto Observe(const Signal& subject, FIn&& func)
-> Observer
{
using REACT_IMPL::IObserver;
using REACT_IMPL::ObserverNode;
using REACT_IMPL::SignalObserverNode;
using REACT_IMPL::AddDefaultReturnValueWrapper;
using F = typename std::decay::type;
using R = typename std::result_of::type;
using WrapperT = AddDefaultReturnValueWrapper;
// If return value of passed function is void, add ObserverAction::next as
// default return value.
using NodeT = typename std::conditional<
std::is_same::value,
SignalObserverNode,
SignalObserverNode
>::type;
const auto& subjectPtr = GetNodePtr(subject);
std::unique_ptr nodePtr( new NodeT(subjectPtr, std::forward(func)) );
ObserverNode* rawNodePtr = nodePtr.get();
subjectPtr->RegisterObserver(std::move(nodePtr));
return Observer( rawNodePtr, subjectPtr );
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/// Observe - Events
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
typename D,
typename FIn,
typename E
>
auto Observe(const Events& subject, FIn&& func)
-> Observer
{
using REACT_IMPL::IObserver;
using REACT_IMPL::ObserverNode;
using REACT_IMPL::EventObserverNode;
using REACT_IMPL::AddDefaultReturnValueWrapper;
using REACT_IMPL::AddObserverRangeWrapper;
using REACT_IMPL::IsCallableWith;
using REACT_IMPL::EventRange;
using F = typename std::decay::type;
using WrapperT =
typename std::conditional<
IsCallableWith::value,
F,
typename std::conditional<
IsCallableWith::value,
AddObserverRangeWrapper,
typename std::conditional<
IsCallableWith::value,
AddDefaultReturnValueWrapper,
typename std::conditional<
IsCallableWith::value,
AddObserverRangeWrapper,
void
>::type
>::type
>::type
>::type;
static_assert(
! std::is_same::value,
"Observe: Passed function does not match any of the supported signatures.");
using NodeT = EventObserverNode;
const auto& subjectPtr = GetNodePtr(subject);
std::unique_ptr nodePtr( new NodeT(subjectPtr, std::forward(func)) );
ObserverNode* rawNodePtr = nodePtr.get();
subjectPtr->RegisterObserver(std::move(nodePtr));
return Observer( rawNodePtr, subjectPtr );
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/// Observe - Synced
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
typename D,
typename FIn,
typename E,
typename ... TDepValues
>
auto Observe(const Events& subject,
const SignalPack& depPack, FIn&& func)
-> Observer
{
using REACT_IMPL::IObserver;
using REACT_IMPL::ObserverNode;
using REACT_IMPL::SyncedObserverNode;
using REACT_IMPL::AddDefaultReturnValueWrapper;
using REACT_IMPL::AddObserverRangeWrapper;
using REACT_IMPL::IsCallableWith;
using REACT_IMPL::EventRange;
using F = typename std::decay::type;
using WrapperT =
typename std::conditional<
IsCallableWith::value,
F,
typename std::conditional<
IsCallableWith::value,
AddObserverRangeWrapper,
typename std::conditional<
IsCallableWith::value,
AddDefaultReturnValueWrapper,
typename std::conditional<
IsCallableWith::value,
AddObserverRangeWrapper,
void
>::type
>::type
>::type
>::type;
static_assert(
! std::is_same::value,
"Observe: Passed function does not match any of the supported signatures.");
using NodeT = SyncedObserverNode;
struct NodeBuilder_
{
NodeBuilder_(const Events& subject, FIn&& func) :
MySubject( subject ),
MyFunc( std::forward(func) )
{}
auto operator()(const Signal& ... deps)
-> ObserverNode*
{
return new NodeT(
GetNodePtr(MySubject), std::forward(MyFunc), GetNodePtr(deps) ... );
}
const Events& MySubject;
FIn MyFunc;
};
const auto& subjectPtr = GetNodePtr(subject);
std::unique_ptr nodePtr( REACT_IMPL::apply(
NodeBuilder_( subject, std::forward(func) ),
depPack.Data) );
ObserverNode* rawNodePtr = nodePtr.get();
subjectPtr->RegisterObserver(std::move(nodePtr));
return Observer( rawNodePtr, subjectPtr );
}
/******************************************/ REACT_END /******************************************/
#endif // REACT_OBSERVER_H_INCLUDED