private static IObservable <T> ObserveFullPropertyPathCore <TNotifier, TProperty, T>(this TNotifier source, NotifyingPath <TNotifier, TProperty> notifyingPath, Func <object?, PropertyChangedEventArgs, T> create, bool signalInitial = true)
            where TNotifier : class, INotifyPropertyChanged
        {
            if (signalInitial)
            {
                return(Observable.Return(
                           create(
                               notifyingPath.SourceAndValue(source).Source,
                               CachedEventArgs.GetOrCreatePropertyChangedEventArgs(string.Empty)))
                       .Concat(source.ObserveFullPropertyPathCore(notifyingPath, create, signalInitial: false)));
            }

            return(Observable.Create <T>(
                       o =>
            {
                var tracker = notifyingPath.CreateTracker(source);
                void Handler(object sender, PropertyChangedEventArgs e) => o.OnNext(create(sender, e));
                foreach (var propertyTracker in tracker)
                {
                    propertyTracker.TrackedPropertyChanged += Handler;
                }

                return Disposable.Create(
                    () =>
                {
                    foreach (var propertyTracker in tracker)
                    {
                        propertyTracker.TrackedPropertyChanged -= Handler;
                    }

                    tracker.Dispose();
                });
            }));
        }
        private static IObservable <T> ObservePropertyChangedCore <TNotifier, TProperty, T>(
            this TNotifier source,
            NotifyingPath <TNotifier, TProperty> notifyingPath,
            Func <object, PropertyChangedEventArgs, T> create,
            bool signalInitial = true)
            where TNotifier : class, INotifyPropertyChanged
        {
            if (signalInitial)
            {
                return(Observable.Return(
                           create(
                               notifyingPath.SourceAndValue(source).Source,
                               CachedEventArgs.GetOrCreatePropertyChangedEventArgs(string.Empty)))
                       .Concat(source.ObservePropertyChangedCore(notifyingPath, create, signalInitial: false)));
            }

            if (notifyingPath.Count > 1)
            {
                return(Observable.Create <T>(
                           o =>
                {
                    var tracker = notifyingPath.CreateTracker(source);
                    void Handler(IPropertyTracker _, object sender, PropertyChangedEventArgs e, SourceAndValue <INotifyPropertyChanged, TProperty> __) => o.OnNext(create(sender, e));
                    tracker.TrackedPropertyChanged += Handler;
                    return new CompositeDisposable(2)
                    {
                        tracker,
                        Disposable.Create(() => tracker.TrackedPropertyChanged -= Handler),
                    };
                }));
            }

            return(ObservePropertyChangedCore(source, notifyingPath.Last.Property.Name, create, signalInitial: false));
        }
        private static IObservable <T> ObserveValueCore <TNotifier, TProperty, T>(
            this TNotifier source,
            NotifyingPath <TNotifier, TProperty> notifyingPath,
            Func <object?, PropertyChangedEventArgs, Maybe <TProperty>, T> create,
            bool signalInitial = true)
            where TNotifier : class, INotifyPropertyChanged
        {
            if (signalInitial)
            {
                return(Observable.Defer(
                           () =>
                {
                    var sourceAndValue = notifyingPath.SourceAndValue(source);
                    return Observable.Return(
                        create(
                            sourceAndValue.Source,
                            CachedEventArgs.GetOrCreatePropertyChangedEventArgs(string.Empty),
                            sourceAndValue.Value));
                })
                       .Concat(source.ObserveValueCore(notifyingPath, create, signalInitial: false)));
            }

            if (notifyingPath.Count > 1)
            {
                return(Observable.Create <T>(
                           o =>
                {
                    var tracker = notifyingPath.CreateTracker(source);
                    tracker.TrackedPropertyChanged += Handler;
                    return new CompositeDisposable(2)
                    {
                        tracker,
                        Disposable.Create(() => tracker.TrackedPropertyChanged -= Handler),
                    };

                    void Handler(IPropertyTracker _, object sender, PropertyChangedEventArgs args, SourceAndValue <INotifyPropertyChanged?, TProperty> sourceAndValue)
                    {
                        o.OnNext(create(sender, args, sourceAndValue.Value));
                    }
                }));
            }

            return(Observable.Create <T>(
                       o =>
            {
                void Handler(object sender, PropertyChangedEventArgs e)
                {
                    if (e.IsMatch(notifyingPath.Last.Property))
                    {
                        var value = notifyingPath.Last.GetMaybe(sender);
                        o.OnNext(create(sender, e, value));
                    }
                }

                source.PropertyChanged += Handler;
                return Disposable.Create(() => source.PropertyChanged -= Handler);
            }));
        }