/// <summary>Dispatch <paramref name="events"/></summary>
        /// <param name="events"></param>
        public void DispatchEvents(ref StructList12 <IEvent> events)
        {
            // Errors
            StructList4 <Exception> errors = new StructList4 <Exception>();

            for (int i = 0; i < events.Count; i++)
            {
                IEvent e = events[i];
                try
                {
                    e?.Observer?.Observer?.OnNext(e);
                }
                catch (Exception error)
                {
                    if (errorHandler != null)
                    {
                        errorHandler(this, e, error);
                    }
                    else
                    {
                        errors.Add(error);
                    }
                }
            }
            if (errors.Count > 0)
            {
                throw new AggregateException(errors.ToArray());
            }
        }
        /// <summary>Dispatch <paramref name="events"/></summary>
        /// <param name="events"></param>
        public void DispatchEvents(IEnumerable <IEvent> events)
        {
            // Errors
            StructList4 <Exception> errors = new StructList4 <Exception>();

            if (events != null)
            {
                foreach (IEvent e in events)
                {
                    try
                    {
                        e?.Observer?.Observer?.OnNext(e);
                    }
                    catch (Exception error)
                    {
                        if (errorHandler != null)
                        {
                            errorHandler(this, e, error);
                        }
                        else
                        {
                            errors.Add(error);
                        }
                    }
                }
            }
            if (errors.Count > 0)
            {
                throw new AggregateException(errors.ToArray());
            }
        }
        /// <summary>Union of <paramref name="o1"/> and <paramref name="o2"/>.</summary>
        public IOption Union(IOption o1, IOption o2)
        {
            StructList4 <IToken> tokens = new StructList4 <IToken>();

            if (o1 is IToken t1)
            {
                foreach (IToken t in t1.ListTokens(true))
                {
                    tokens.AddIfNew(t);
                }
            }
            if (o2 is IToken t2)
            {
                foreach (IToken t in t2.ListTokens(true))
                {
                    tokens.AddIfNew(t);
                }
            }
            if (tokens.Count == 0)
            {
                return(TokenList.NoTokens);
            }
            if (tokens.Count == 1)
            {
                return(tokens[0]);
            }
            return(new TokenList(tokens.ToArray()));
        }
 /// <summary>Dispose called by finalizer or consumer (on Dispose())</summary>
 protected virtual void Dispose(bool disposing)
 {
     if (disposing)
     {
         // Cancel source
         CancelSrc.Dispose();
         // Array of observer handles
         var handles = observers.Array;
         // Errors
         StructList4 <Exception> errors = new StructList4 <Exception>();
         foreach (var handle in handles)
         {
             try
             {
                 handle.observer.OnCompleted();
             }
             catch (Exception e)
             {
                 // Add observer exception as error event, but don't dispatch it.
                 Events.TryAdd(new OperationErrorEvent(null, e));
                 // Capture
                 errors.Add(e);
             }
         }
         if (errors.Count > 0)
         {
             throw new AggregateException(errors.ToArray());
         }
     }
 }
        /// <summary>
        /// Concatenates three tokens non-recursively.
        /// Tokens may be null valued.
        /// </summary>
        /// <param name="t1">(optional) Token</param>
        /// <param name="t2">(optional) Token</param>
        /// <param name="t3">(optional) Token</param>
        /// <returns>null, t1, t2, or concatenated token</returns>
        public static IToken Concat(this IToken t1, IToken t2, IToken t3)
        {
            StructList4 <IToken> tokens = new StructList4 <IToken>();

            if (t1 != null)
            {
                if (t1 is ITokenEnumerable enumr)
                {
                    foreach (IToken t in enumr)
                    {
                        tokens.AddIfNew(t);
                    }
                }
                else
                {
                    tokens.AddIfNew(t1);
                }
            }
            if (t2 != null)
            {
                if (t2 is ITokenEnumerable enumr)
                {
                    foreach (IToken t in enumr)
                    {
                        tokens.AddIfNew(t);
                    }
                }
                else
                {
                    tokens.AddIfNew(t2);
                }
            }
            if (t3 != null)
            {
                if (t3 is ITokenEnumerable enumr)
                {
                    foreach (IToken t in enumr)
                    {
                        tokens.AddIfNew(t);
                    }
                }
                else
                {
                    tokens.AddIfNew(t3);
                }
            }
            if (tokens.Count == 0)
            {
                return(null);
            }
            if (tokens.Count == 1)
            {
                return(tokens[0]);
            }
            return(new TokenList(tokens.ToArray()));
        }
        /// <summary>
        /// If <paramref name="tokenContainer"/> is a single token, then enumerates it.
        /// If <paramref name="tokenContainer"/> is token collection, then enumerates all contained tokens.
        /// If <paramref name="recurse"/> is true, then enumerates tree of collections.
        /// </summary>
        /// <param name="tokenContainer"></param>
        /// <param name="recurse"></param>
        /// <returns>enumerable of tokens</returns>
        public static IEnumerable <IToken> ListTokens(this IOption tokenContainer, bool recurse = true)
        {
            // Is a token
            if (tokenContainer is IToken token)
            {
                // Enumerable
                if (tokenContainer is ITokenEnumerable enumr)
                {
                    // Return enumerable as is
                    if (!recurse)
                    {
                        return(enumr);
                    }

                    // Put into queue
                    StructList4 <IToken> queue = new StructList4 <IToken>();
                    foreach (IToken t in enumr)
                    {
                        queue.Add(t);
                    }
                    StructListSorter <StructList4 <IToken>, IToken> .Reverse(ref queue);

                    StructList4 <IToken> result = new StructList4 <IToken>();
                    while (queue.Count > 0)
                    {
                        int    ix = queue.Count - 1;
                        IToken t  = queue[ix];
                        queue.RemoveAt(ix);

                        if (t is ITokenEnumerable enumr_)
                        {
                            foreach (IToken tt in enumr_)
                            {
                                queue.Add(tt);
                            }
                        }
                        else
                        {
                            result.Add(t);
                        }
                    }
                    return(result.ToArray());
                }
                // Single token
                else
                {
                    return new IToken[] { token }
                };
            }
            else
            {
                // No tokens
                return(no_tokens);
            }
        }
        /// <summary>
        /// Create a token that reads <paramref name="tokens"/> into array of tokens.
        /// Removes null values.
        /// </summary>
        /// <param name="tokens"></param>
        public TokenList(IEnumerable <IToken> tokens)
        {
            StructList4 <IToken> list = new StructList4 <IToken>();

            foreach (var t in tokens)
            {
                if (t != null)
                {
                    list.Add(t);
                }
            }
            this.tokens = list.ToArray();
        }
        /// <summary>Forward events to observers.</summary>
        /// <param name="events">IEnumerable or <see cref="IEvent"/></param>
        protected void processEvents(object events)
        {
            // Errors
            StructList4 <Exception> errors = new StructList4 <Exception>();

            if (events is IEnumerable <IEvent> eventsEnumr)
            {
                foreach (IEvent e in eventsEnumr)
                {
                    try
                    {
                        e?.Observer?.Observer?.OnNext(e);
                    }
                    catch (Exception error)
                    {
                        if (errorHandler != null)
                        {
                            errorHandler(this, e, error);
                        }
                        else
                        {
                            errors.Add(error);
                        }
                    }
                }
                if (errors.Count > 0)
                {
                    throw new AggregateException(errors.ToArray());
                }
            }
            else if (events is IEvent @event)
            {
                try
                {
                    @event.Observer?.Observer?.OnNext(@event);
                }
                catch (Exception error) when(errorHandler != null)
                {
                    errorHandler(this, @event, error);
                }
            }
        }
        /// <summary>Flatten to simpler instance.</summary>
        public IOption Flatten(IOption o)
        {
            StructList4 <IToken> tokens = new StructList4 <IToken>();

            if (o is IToken t_)
            {
                foreach (IToken t in t_.ListTokens(true))
                {
                    tokens.AddIfNew(t);
                }
            }
            if (tokens.Count == 0)
            {
                return(TokenList.NoTokens);
            }
            if (tokens.Count == 1)
            {
                return(tokens[0]);
            }
            return(new TokenList(tokens.ToArray()));
        }