private bool Read( StreamingUnpacker unpacker, UnpackingMode unpackingMode )
		{
			while ( !this.IsInStreamTail() )
			{
				var data = unpacker.Unpack( this._currentSource.Stream, unpackingMode );
				if ( data != null )
				{
					this._data = data;
					return true;
				}
				else
				{
					this._mayInTail = true;
				}
			}

			return false;
		}
		private bool UnpackRawLength( Stream source, UnpackingMode unpackingMode, out MessagePackObject? unpacked )
		{
			int feeded;
			this._bytesBuffer = this._bytesBuffer.Feed( source, out feeded );
			this._readByteLength += feeded;

			if ( this._bytesBuffer.IsFilled )
			{
				var length = this._bytesBuffer.AsUInt32();
				if ( length == 0 )
				{
					// empty collection
					if ( unpackingMode == UnpackingMode.SkipSubtree )
					{
						// Set dummy
						unpacked = MessagePackObject.Nil;
					}
					else
					{
						unpacked = CreateEmptyCollection( this._contextValueHeader );
					}

					// Empty raw is not considered as EmptyCollection.
					return true;
				}

				this.TransitToUnpackRawBytes( length );

				return this.UnpackRawBytes( source, unpackingMode, out unpacked );
			}

			// Need more info.
			unpacked = null;
			return false;
		}
		private bool UnpackRawBytes( Stream source, UnpackingMode unpackingMode, out MessagePackObject? unpacked )
		{
#if DEBUG
			Contract.Assert( this._bytesBuffer.BackingStore != null, this._bytesBuffer.ToString() );
#endif

			int feeded;
			this._bytesBuffer = this._bytesBuffer.Feed( source, out feeded );
			this._readByteLength += feeded;
			if ( this._bytesBuffer.IsFilled )
			{
				if ( unpackingMode == UnpackingMode.SkipSubtree )
				{
					// Set dummy
					unpacked = MessagePackObject.Nil;
				}
				else
				{
					unpacked = this._bytesBuffer.AsMessagePackObject( this._contextValueHeader.Type );
				}

				return true;
			}

			// Need more info.
			unpacked = null;
			return false;
		}
		private bool UnpackHeader( Stream source, UnpackingMode unpackingMode, out MessagePackObject? result )
		{
			var b = source.ReadByte();
			if ( b < 0 )
			{
				result = null;
				return false;
			}

			this._readByteLength++;
			this._contextValueHeader = _headerArray[ b ];
			return _headerUnpackings[ b ]( this, b, source, unpackingMode, out result );
		}
		private bool UnpackCollectionLength( Stream source, UnpackingMode unpackingMode, out MessagePackObject? unpacked )
		{
			int feeded;
			this._bytesBuffer = this._bytesBuffer.Feed( source, out feeded );
			this._readByteLength += feeded;

			if ( this._bytesBuffer.IsFilled )
			{
				// new collection

				var length = this._bytesBuffer.AsUInt32();
				if ( length == 0 )
				{
					// empty collection
					if ( unpackingMode == UnpackingMode.SkipSubtree )
					{
						// Set dummy
						unpacked = MessagePackObject.Nil;
					}
					else
					{
						unpacked = CreateEmptyCollection( this._contextValueHeader );
					}

					this._lastEmptyCollection = ToEmptyCollectionType( this._contextValueHeader.Type );
					return true;
				}

				this._collectionState.NewContextCollection( this._contextValueHeader, length );
				this.TransitToUnpackContextCollection();

				unpacked = null;
				return true;
			}

			// Try next iteration.
			unpacked = null;
			return false;
		}
		private static bool UnpackArrayOrMapHeader( StreamingUnpacker @this, int b, Stream source, UnpackingMode unpackingMode, out MessagePackObject? result )
		{
			// Transit to UnpackCollectionLength
			@this._next = @this._unpackCollectionLength;
			@this._isInCollection = false;
			@this._bytesBuffer = ( b % 2 ) == 0 ? BytesBuffer.TwoBytes : BytesBuffer.FourBytes;

			if ( [email protected]( source, unpackingMode, out result ) )
			{
				// Need to get more data
				return false;
			}

			return true;
		}
		private static bool ThrowInvalidHeaderException( StreamingUnpacker @this, int b, Stream source, UnpackingMode unpackingMode, out MessagePackObject? result )
		{
			throw new MessageTypeException( String.Format( CultureInfo.CurrentCulture, "Header '0x{0:x2}' is not available.", b ) );
		}
		private static bool UnpackScalarHeader( StreamingUnpacker @this, int b, Stream source, UnpackingMode unpackingMode, out MessagePackObject? result )
		{
			// Transit to UnpackScalar
			@this._next = @this._unpackScalar;
			@this._isInCollection = false;
			@this._bytesBuffer = _scalarBuffers[ b % 4 ];

			// Try to get body.
			if ( [email protected]( source, unpackingMode, out result ) )
			{
				// Need more data
				return false;
			}

			return true;
		}
		private static bool UnpackRawHeader( StreamingUnpacker @this, int b, Stream source, UnpackingMode unpackingMode, out MessagePackObject? result )
		{
			@this._next = @this._unpackRawLength;
			@this._isInCollection = false;
			@this._bytesBuffer = ( b % 2 ) == 0 ? BytesBuffer.TwoBytes : BytesBuffer.FourBytes;

			// Try to get length.
			return @this.UnpackRawLength( source, unpackingMode, out result );
		}
		private static bool UnpackFixRawLength( StreamingUnpacker @this, int b, Stream source, UnpackingMode unpackingMode, out MessagePackObject? result )
		{
			@this.TransitToUnpackRawBytes( unchecked( ( uint )( b & 0x1f ) ) );
			// Try to get body.
			return @this.UnpackRawBytes( source, unpackingMode, out result );
		}
		private static bool UnpackTrue( StreamingUnpacker @this, int b, Stream source, UnpackingMode unpackingMode, out MessagePackObject? result )
		{
			result = _true;
			return true;
		}
		private static bool UnpackEmptyRaw( StreamingUnpacker @this, int b, Stream source, UnpackingMode unpackingMode, out MessagePackObject? result )
		{
			result = _emptyBinary;
			@this._lastEmptyCollection = EmptyCollectionType.Raw;
			return true;
		}
		private static bool UnpackFixArrayLength( StreamingUnpacker @this, int b, Stream source, UnpackingMode unpackingMode, out MessagePackObject? result )
		{
			var header = _headerArray[ b ];
			@this._collectionState.NewContextCollection( header, header.ValueOrLength );
			result = null;
			@this.TransitToUnpackContextCollection();
			return true;
		}
		private static bool UnpackEmptyArray( StreamingUnpacker @this, int b, Stream source, UnpackingMode unpackingMode, out MessagePackObject? result )
		{
			result = new MessagePackObject( _emptyArray, true );
			@this._lastEmptyCollection = EmptyCollectionType.Array;
			return true;
		}
		private static bool UnpackNegativeFixNum( StreamingUnpacker @this, int b, Stream source, UnpackingMode unpackingMode, out MessagePackObject? result )
		{
			result = _negavieFixNums[ b & 0x1f ];
			return true;
		}
		/// <summary>
		///		Try unpack object from specified source.
		/// </summary>
		/// <param name="source">Input source to unpack.</param>
		/// <param name="unpackingMode"><see cref="UnpackingMode"/> that controls unpacking flow.</param>
		/// <returns>
		///		Unpacked entry. The mean of the entry depends on specified <paramref name="unpackingMode"/>.
		/// </returns>
		/// <remarks>
		///		<para>
		///			When this method returns null, caller can feed extra bytes to <paramref name="source"/> and invoke this again. 
		///			It could succeed because this instance preserves previous invocation state, and required bytes are supplied.
		///		</para>
		///		<para>
		///			When this method completes unpackaging single <see cref="MessagePackObject"/> tree,
		///			this method stops iterating <paramref name="source"/> (via <see cref="IEnumerator&lt;T&gt;"/>.
		///			This behavior is notified via <see cref="IDisposable.Dispose">IEnumerator&lt;T&gt;.Dispose()</see> method.
		///		</para>
		/// </remarks>
		public MessagePackObject? Unpack( Stream source, UnpackingMode unpackingMode )
		{
			// FIXME:BULK LOAD
			Contract.Assert( source != null );

			this._lastEmptyCollection = EmptyCollectionType.None;

			MessagePackObject? collectionItemOrRoot;
			while ( this._next( source, unpackingMode, out collectionItemOrRoot ) )
			{
				if ( collectionItemOrRoot != null )
				{
					int depth = this._collectionState.Depth;
					var root = this.AddToContextCollection( collectionItemOrRoot.Value );
					this._hasMoreEntries = depth <= this._collectionState.Depth;

					if ( root != null )
					{
#if DEBUG
						Contract.Assert( this._collectionState.IsEmpty );
#endif
						this._next = this._unpackHeader;
						this._isInCollection = false;
#if DEBUG
						Contract.Assert( this._contextValueHeader.Type == MessageType.Unknown, this._contextValueHeader.ToString() );// null
						Contract.Assert( this._bytesBuffer.BackingStore == null, this._bytesBuffer.ToString() ); // null
#endif
						if ( unpackingMode == UnpackingMode.PerEntry )
						{
							if ( this._lastEmptyCollection != EmptyCollectionType.None )
							{
								// It was empty collection.
								return 0;
							}
							else
							{
								// Last item
								return collectionItemOrRoot.Value;
							}
						}
						else
						{
							// Length
							var readByteLength = this._readByteLength;
							this._readByteLength = 0L;
							return readByteLength;
						}
					}
				}
				else
				{
					this._hasMoreEntries = true;
				}

				// There are more entries in the tree.
				if ( unpackingMode == UnpackingMode.PerEntry )
				{
					// The unpacker may return unpacked collection item.
					if ( this._isInCollection )
					{
						if ( this._collectionState.UnpackedItemsCount == 0 )
						{
							// Count
							return this._collectionState.UnpackingItemsCount;
						}
						else if ( this._lastEmptyCollection != EmptyCollectionType.None )
						{
							// Empty nested collection.
							return 0;
						}
						else
						{
							Contract.Assert( collectionItemOrRoot.HasValue );
							return collectionItemOrRoot.Value;
						}
					}
				}
			}

			return null;
		}