private static IObservable <T> Tween <T>(Func <OperationalStructBase <T> > start, Func <OperationalStructBase <T> > finish, Func <float> duration, EaseType easeType, LoopType loopType, Action onCompleteTween, bool ignoreTimeScale) where T : struct
        {
            T startValue  = default;
            T finishValue = default;

            onCompleteTween = onCompleteTween ?? (() => { });

            IDisposable ReturnStartValue(IObserver <T> observer)
            {
                observer.OnNext(startValue);
                return(null);
            }

            IDisposable ReturnFinishValue(IObserver <T> observer)
            {
                observer.OnNext(finishValue);
                return(null);
            }

            IObservable <T> stream = Observable.Empty <TweenInformation <T> >()
                                     // Repeat() のために、毎回初期値を生成
                                     .StartWith(() => new TweenInformation <T>(ignoreTimeScale ? Time.unscaledTime : Time.time, start(), finish(), duration(), easeType, out startValue, out finishValue))
                                     // Update のストリームに変換
                                     .SelectMany(information => Observable.Interval(TimeSpan.FromMilliseconds(1), ignoreTimeScale ? Scheduler.MainThreadIgnoreTimeScale : Scheduler.MainThread).Do(_ => information.Time = (ignoreTimeScale ? Time.unscaledTime : Time.time) - information.StartTime).Select(_ => information))
                                     // Tween 時間が処理時間よりも小さい間流し続ける
                                     .TakeWhile(information => information.Time <= information.Duration)
                                     // 実際の Easing 処理実行
                                     .Select(information => Easing(information.Time, information.Start, (information.Finish - information.Start), information.Duration, information.EaseType).Value)
                                     // 最終フレームの値を確実に流すために OnCompleted が来たら値を一つ流すストリームに繋ぐ
                                     // 1回分の Tween が終わったらコールバックを呼ぶ
                                     .Concat(Observable.Create((Func <IObserver <T>, IDisposable>)ReturnFinishValue).Take(1).Do(_ => onCompleteTween()));

            switch (loopType)
            {
            case LoopType.None:
                // Do nothing.
                break;

            case LoopType.Repeat:
                stream = stream.Repeat();
                break;

            case LoopType.PingPong:
                stream = stream
                         .Concat(
                    Observable.Empty <TweenInformation <T> >()
                    // Repeat() のために、毎回初期値を生成
                    .StartWith(() => new TweenInformation <T>(ignoreTimeScale ? Time.unscaledTime : Time.time, start(), finish(), duration(), easeType, out startValue, out finishValue))
                    // Update のストリームに変換
                    .SelectMany(information => Observable.Interval(TimeSpan.FromMilliseconds(1), ignoreTimeScale ? Scheduler.MainThreadIgnoreTimeScale : Scheduler.MainThread).Do(_ => information.Time = (ignoreTimeScale ? Time.unscaledTime : Time.time) - information.StartTime).Select(_ => information))
                    // Tween 時間が処理時間よりも小さい間流し続ける
                    .TakeWhile(information => information.Time <= information.Duration)
                    // start と finish を入れ替えて、実際の Easing 処理実行
                    .Select(information => Easing(information.Time, information.Finish, (information.Start - information.Finish), information.Duration, information.EaseType).Value)
                    // 最終フレームの値を確実に流すために OnCompleted が来たら最終値を一つ流すストリームに繋ぐ
                    // 1回分の Tween が終わったらコールバックを呼ぶ
                    .Concat(Observable.Create((Func <IObserver <T>, IDisposable>)ReturnStartValue).Take(1).Do(_ => onCompleteTween()))
                    )
                         .Repeat();
                break;

            case LoopType.Mirror:
                stream = stream
                         .Concat(
                    Observable.Empty <TweenInformation <T> >()
                    // Repeat() のために、毎回初期値を生成
                    .StartWith(() => new TweenInformation <T>(ignoreTimeScale ? Time.unscaledTime : Time.time, start(), finish(), duration(), easeType, out startValue, out finishValue))
                    // Update のストリームに変換
                    .SelectMany(information => Observable.Interval(TimeSpan.FromMilliseconds(1), ignoreTimeScale ? Scheduler.MainThreadIgnoreTimeScale : Scheduler.MainThread).Do(_ => information.Time = (ignoreTimeScale ? Time.unscaledTime : Time.time) - information.StartTime).Select(_ => information))
                    // Tween 時間が処理時間よりも小さい間流し続ける
                    .TakeWhile(information => information.Time <= information.Duration)
                    // start と finish を入れ替えて、実際の Easing 処理実行
                    .Select(information => Easing(information.Time, information.Finish, (information.Start - information.Finish), information.Duration, MirrorEaseTypeMap[information.EaseType]).Value)
                    // 最終フレームの値を確実に流すために OnCompleted が来たら最終値を一つ流すストリームに繋ぐ
                    // 1回分の Tween が終わったらコールバックを呼ぶ
                    .Concat(Observable.Create((Func <IObserver <T>, IDisposable>)ReturnStartValue).Take(1).Do(_ => onCompleteTween()))
                    )
                         .Repeat();
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(loopType), loopType, null);
            }

            return(stream);
        }