Bug 1287246 (Part 1) - Expose LexerResult from the StreamingLexer API and add an explicit Yield type. r=njn
authorSeth Fowler <mark.seth.fowler@gmail.com>
Fri, 15 Jul 2016 22:27:12 -0700
changeset 345408 3ce690bdd3a87b4af237e2bb0cc2391a62832d0a
parent 345407 6bcb97503de4fe93f58b4930b368b6f86650076a
child 345409 d858390c1386134041658ba79e4bdae6c5b29ba7
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs1287246
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1287246 (Part 1) - Expose LexerResult from the StreamingLexer API and add an explicit Yield type. r=njn
image/Decoder.cpp
image/Decoder.h
image/StreamingLexer.h
image/decoders/nsBMPDecoder.cpp
image/decoders/nsBMPDecoder.h
image/decoders/nsGIFDecoder2.cpp
image/decoders/nsGIFDecoder2.h
image/decoders/nsICODecoder.cpp
image/decoders/nsICODecoder.h
image/decoders/nsIconDecoder.cpp
image/decoders/nsIconDecoder.h
image/decoders/nsJPEGDecoder.cpp
image/decoders/nsJPEGDecoder.h
image/decoders/nsPNGDecoder.cpp
image/decoders/nsPNGDecoder.h
image/test/gtest/TestStreamingLexer.cpp
--- a/image/Decoder.cpp
+++ b/image/Decoder.cpp
@@ -112,36 +112,38 @@ Decoder::Decode(IResumable* aOnResume /*
   MOZ_ASSERT(mInitialized, "Should be initialized here");
   MOZ_ASSERT(mIterator, "Should have a SourceBufferIterator");
 
   // If we're already done, don't attempt to keep decoding.
   if (GetDecodeDone()) {
     return HasError() ? NS_ERROR_FAILURE : NS_OK;
   }
 
-  Maybe<TerminalState> terminalState;
+  LexerResult lexerResult(TerminalState::FAILURE);
   {
     PROFILER_LABEL("ImageDecoder", "Decode", js::ProfileEntry::Category::GRAPHICS);
     AutoRecordDecoderTelemetry telemetry(this);
 
-    terminalState = DoDecode(*mIterator, aOnResume);
-  }
+    lexerResult =  DoDecode(*mIterator, aOnResume);
+  };
 
-  if (!terminalState) {
+  if (lexerResult.is<Yield>()) {
     // We need more data to continue. If @aOnResume was non-null, the
     // SourceBufferIterator will automatically reschedule us. Otherwise, it's up
     // to the caller.
+    MOZ_ASSERT(lexerResult.as<Yield>() == Yield::NEED_MORE_DATA);
     return NS_OK;
   }
 
   // We reached a terminal state; we're now done decoding.
+  MOZ_ASSERT(lexerResult.is<TerminalState>());
   mReachedTerminalState = true;
 
   // If decoding failed, record that fact.
-  if (terminalState == Some(TerminalState::FAILURE)) {
+  if (lexerResult.as<TerminalState>() == TerminalState::FAILURE) {
     PostError();
   }
 
   // Perform final cleanup.
   CompleteDecode();
 
   return HasError() ? NS_ERROR_FAILURE : NS_OK;
 }
--- a/image/Decoder.h
+++ b/image/Decoder.h
@@ -292,18 +292,18 @@ protected:
    * Internal hooks. Decoder implementations may override these and
    * only these methods.
    *
    * BeforeFinishInternal() can be used to detect if decoding is in an
    * incomplete state, e.g. due to file truncation, in which case it should
    * return a failing nsresult.
    */
   virtual nsresult InitInternal();
-  virtual Maybe<TerminalState> DoDecode(SourceBufferIterator& aIterator,
-                                        IResumable* aOnResume) = 0;
+  virtual LexerResult DoDecode(SourceBufferIterator& aIterator,
+                               IResumable* aOnResume) = 0;
   virtual nsresult BeforeFinishInternal();
   virtual nsresult FinishInternal();
   virtual nsresult FinishWithErrorInternal();
 
   /*
    * Progress notifications.
    */
 
--- a/image/StreamingLexer.h
+++ b/image/StreamingLexer.h
@@ -33,18 +33,24 @@ enum class BufferingStrategy
 
 /// Possible terminal states for the lexer.
 enum class TerminalState
 {
   SUCCESS,
   FAILURE
 };
 
+/// Possible yield reasons for the lexer.
+enum class Yield
+{
+  NEED_MORE_DATA  // The lexer cannot continue without more data.
+};
+
 /// The result of a call to StreamingLexer::Lex().
-typedef Variant<TerminalState> LexerResult;
+typedef Variant<TerminalState, Yield> LexerResult;
 
 /**
  * LexerTransition is a type used to give commands to the lexing framework.
  * Code that uses StreamingLexer can create LexerTransition values using the
  * static methods on Transition, and then return them to the lexing framework
  * for execution.
  */
 template <typename State>
@@ -224,23 +230,23 @@ private:
  *    return in turn.
  *
  *  - Write the methods that actually implement lexing for your image format.
  *    These methods should return either Transition::To(), to move on to another
  *    state, or Transition::Terminate{Success,Failure}(), if lexing has
  *    terminated in either success or failure. (There are also additional
  *    transitions for unbuffered reads; see below.)
  *
- * That's all there is to it. The StreamingLexer will track your position in the
- * input and buffer enough data so that your lexing methods can process
- * everything in one pass. Lex() returns Nothing() if more data is needed, in
+ * That's the basics. The StreamingLexer will track your position in the input
+ * and buffer enough data so that your lexing methods can process everything in
+ * one pass. Lex() returns Yield::NEED_MORE_DATA if more data is needed, in
  * which case you should just return from DoDecode(). If lexing reaches a
- * terminal state, Lex() returns Some(State::SUCCESS) or Some(State::FAILURE),
- * and you can check which one to determine if lexing succeeded or failed and do
- * any necessary cleanup.
+ * terminal state, Lex() returns TerminalState::SUCCESS or
+ * TerminalState::FAILURE, and you can check which one to determine if lexing
+ * succeeded or failed and do any necessary cleanup.
  *
  * There's one more wrinkle: some lexers may want to *avoid* buffering in some
  * cases, and just process the data as it comes in. This is useful if, for
  * example, you just want to skip over a large section of data; there's no point
  * in buffering data you're just going to ignore.
  *
  * You can begin an unbuffered read with Transition::ToUnbuffered(). This works
  * a little differently than Transition::To() in that you specify *two* states.
@@ -264,41 +270,42 @@ public:
   explicit StreamingLexer(LexerTransition<State> aStartState)
     : mTransition(TerminalState::FAILURE)
     , mToReadUnbuffered(0)
   {
     SetTransition(aStartState);
   }
 
   template <typename Func>
-  Maybe<TerminalState> Lex(SourceBufferIterator& aIterator,
-                           IResumable* aOnResume,
-                           Func aFunc)
+  LexerResult Lex(SourceBufferIterator& aIterator,
+                  IResumable* aOnResume,
+                  Func aFunc)
   {
     if (mTransition.NextStateIsTerminal()) {
       // We've already reached a terminal state. We never deliver any more data
       // in this case; just return the terminal state again immediately.
-      return Some(mTransition.NextStateAsTerminal());
+      return LexerResult(mTransition.NextStateAsTerminal());
     }
 
     Maybe<LexerResult> result;
     do {
       // Figure out how much we need to read.
       const size_t toRead = mTransition.Buffering() == BufferingStrategy::UNBUFFERED
                           ? mToReadUnbuffered
                           : mTransition.Size() - mBuffer.length();
 
       // Attempt to advance the iterator by |toRead| bytes.
       switch (aIterator.AdvanceOrScheduleResume(toRead, aOnResume)) {
         case SourceBufferIterator::WAITING:
           // We can't continue because the rest of the data hasn't arrived from
           // the network yet. We don't have to do anything special; the
           // SourceBufferIterator will ensure that |aOnResume| gets called when
           // more data is available.
-          return Nothing();
+          result = Some(LexerResult(Yield::NEED_MORE_DATA));
+          break;
 
         case SourceBufferIterator::COMPLETE:
           // Normally even if the data is truncated, we want decoding to
           // succeed so we can display whatever we got. However, if the
           // SourceBuffer was completed with a failing status, we want to fail.
           // This happens only in exceptional situations like SourceBuffer
           // itself encountering a failure due to OOM.
           result = SetTransition(NS_SUCCEEDED(aIterator.CompletionStatus())
@@ -316,19 +323,17 @@ public:
           break;
 
         default:
           MOZ_ASSERT_UNREACHABLE("Unknown SourceBufferIterator state");
           result = SetTransition(Transition::TerminateFailure());
       }
     } while (!result);
 
-    // Map |LexerResult| onto the old |Maybe<TerminalState>| API.
-    return result->is<TerminalState>() ? Some(result->as<TerminalState>())
-                                       : Nothing();
+    return *result;
   }
 
 private:
   template <typename Func>
   Maybe<LexerResult> UnbufferedRead(SourceBufferIterator& aIterator, Func aFunc)
   {
     MOZ_ASSERT(mTransition.Buffering() == BufferingStrategy::UNBUFFERED);
     MOZ_ASSERT(mBuffer.empty(),
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -441,17 +441,17 @@ nsBMPDecoder::FinishRow()
                        Some(invalidRect.mTargetSizeRect));
     }
   } else {
     PostInvalidation(IntRect(0, mCurrentRow, mH.mWidth, 1));
   }
   mCurrentRow--;
 }
 
-Maybe<TerminalState>
+LexerResult
 nsBMPDecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
 
   return mLexer.Lex(aIterator, aOnResume,
                     [=](State aState, const char* aData, size_t aLength) {
     switch (aState) {
       case State::FILE_HEADER:      return ReadFileHeader(aData, aLength);
--- a/image/decoders/nsBMPDecoder.h
+++ b/image/decoders/nsBMPDecoder.h
@@ -137,18 +137,18 @@ public:
   /// Mark this BMP as being within an ICO file. Only used for testing purposes
   /// because the ICO-specific constructor does this marking automatically.
   void SetIsWithinICO() { mIsWithinICO = true; }
 
   /// Did the BMP file have alpha data of any kind? (Only use this after the
   /// bitmap has been fully decoded.)
   bool HasTransparency() const { return mDoesHaveTransparency; }
 
-  Maybe<TerminalState> DoDecode(SourceBufferIterator& aIterator,
-                                IResumable* aOnResume) override;
+  LexerResult DoDecode(SourceBufferIterator& aIterator,
+                       IResumable* aOnResume) override;
   nsresult BeforeFinishInternal() override;
   nsresult FinishInternal() override;
 
 private:
   friend class DecoderFactory;
 
   enum class State {
     FILE_HEADER,
--- a/image/decoders/nsGIFDecoder2.cpp
+++ b/image/decoders/nsGIFDecoder2.cpp
@@ -451,17 +451,17 @@ ConvertColormap(uint32_t* aColormap, uin
   // copy remaining pixel(s)
   // NB: can't use 32-bit reads, they might read off the end of the buffer
   while (c--) {
     from -= 3;
     *--to = gfxPackedPixel(0xFF, from[0], from[1], from[2]);
   }
 }
 
-Maybe<TerminalState>
+LexerResult
 nsGIFDecoder2::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
 
   return mLexer.Lex(aIterator, aOnResume,
                     [=](State aState, const char* aData, size_t aLength) {
     switch(aState) {
       case State::GIF_HEADER:
--- a/image/decoders/nsGIFDecoder2.h
+++ b/image/decoders/nsGIFDecoder2.h
@@ -19,18 +19,18 @@ class RasterImage;
 //////////////////////////////////////////////////////////////////////
 // nsGIFDecoder2 Definition
 
 class nsGIFDecoder2 : public Decoder
 {
 public:
   ~nsGIFDecoder2();
 
-  Maybe<TerminalState> DoDecode(SourceBufferIterator& aIterator,
-                                IResumable* aOnResume) override;
+  LexerResult DoDecode(SourceBufferIterator& aIterator,
+                       IResumable* aOnResume) override;
   nsresult FinishInternal() override;
   virtual Telemetry::ID SpeedHistogram() override;
 
 private:
   friend class DecoderFactory;
 
   // Decoders should only be instantiated via DecoderFactory.
   explicit nsGIFDecoder2(RasterImage* aImage);
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -583,17 +583,17 @@ nsICODecoder::FinishResource()
   if (mContainedDecoder->HasSize() &&
       mContainedDecoder->GetSize() != GetRealSize()) {
     return Transition::TerminateFailure();
   }
 
   return Transition::TerminateSuccess();
 }
 
-Maybe<TerminalState>
+LexerResult
 nsICODecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
 
   return mLexer.Lex(aIterator, aOnResume,
                     [=](ICOState aState, const char* aData, size_t aLength) {
     switch (aState) {
       case ICOState::HEADER:
--- a/image/decoders/nsICODecoder.h
+++ b/image/decoders/nsICODecoder.h
@@ -64,18 +64,18 @@ public:
   gfx::IntSize GetRealSize() const
   {
     return gfx::IntSize(GetRealWidth(), GetRealHeight());
   }
 
   /// @return The offset from the beginning of the ICO to the first resource.
   size_t FirstResourceOffset() const;
 
-  Maybe<TerminalState> DoDecode(SourceBufferIterator& aIterator,
-                                IResumable* aOnResume) override;
+  LexerResult DoDecode(SourceBufferIterator& aIterator,
+                       IResumable* aOnResume) override;
   nsresult FinishInternal() override;
   nsresult FinishWithErrorInternal() override;
 
 private:
   friend class DecoderFactory;
 
   // Decoders should only be instantiated via DecoderFactory.
   explicit nsICODecoder(RasterImage* aImage);
--- a/image/decoders/nsIconDecoder.cpp
+++ b/image/decoders/nsIconDecoder.cpp
@@ -21,17 +21,17 @@ nsIconDecoder::nsIconDecoder(RasterImage
  , mBytesPerRow()   // set by ReadHeader()
 {
   // Nothing to do
 }
 
 nsIconDecoder::~nsIconDecoder()
 { }
 
-Maybe<TerminalState>
+LexerResult
 nsIconDecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
 
   return mLexer.Lex(aIterator, aOnResume,
                     [=](State aState, const char* aData, size_t aLength) {
     switch (aState) {
       case State::HEADER:
--- a/image/decoders/nsIconDecoder.h
+++ b/image/decoders/nsIconDecoder.h
@@ -32,18 +32,18 @@ class RasterImage;
 //
 ////////////////////////////////////////////////////////////////////////////////
 
 class nsIconDecoder : public Decoder
 {
 public:
   virtual ~nsIconDecoder();
 
-  Maybe<TerminalState> DoDecode(SourceBufferIterator& aIterator,
-                                IResumable* aOnResume) override;
+  LexerResult DoDecode(SourceBufferIterator& aIterator,
+                       IResumable* aOnResume) override;
 
 private:
   friend class DecoderFactory;
 
   // Decoders should only be instantiated via DecoderFactory.
   explicit nsIconDecoder(RasterImage* aImage);
 
   enum class State {
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -177,17 +177,17 @@ nsJPEGDecoder::FinishInternal()
       (mState != JPEG_ERROR) &&
       !IsMetadataDecode()) {
     mState = JPEG_DONE;
   }
 
   return NS_OK;
 }
 
-Maybe<TerminalState>
+LexerResult
 nsJPEGDecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
 
   return mLexer.Lex(aIterator, aOnResume,
                     [=](State aState, const char* aData, size_t aLength) {
     switch (aState) {
       case State::JPEG_DATA:
--- a/image/decoders/nsJPEGDecoder.h
+++ b/image/decoders/nsJPEGDecoder.h
@@ -53,18 +53,18 @@ public:
   virtual ~nsJPEGDecoder();
 
   virtual void SetSampleSize(int aSampleSize) override
   {
     mSampleSize = aSampleSize;
   }
 
   nsresult InitInternal() override;
-  Maybe<TerminalState> DoDecode(SourceBufferIterator& aIterator,
-                                IResumable* aOnResume) override;
+  LexerResult DoDecode(SourceBufferIterator& aIterator,
+                       IResumable* aOnResume) override;
   nsresult FinishInternal() override;
 
   virtual Telemetry::ID SpeedHistogram() override;
   void NotifyDone();
 
 protected:
   Orientation ReadOrientationFromEXIF();
   void OutputScanlines(bool* suspend);
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -342,17 +342,17 @@ nsPNGDecoder::InitInternal()
   png_set_progressive_read_fn(mPNG, static_cast<png_voidp>(this),
                               nsPNGDecoder::info_callback,
                               nsPNGDecoder::row_callback,
                               nsPNGDecoder::end_callback);
 
   return NS_OK;
 }
 
-Maybe<TerminalState>
+LexerResult
 nsPNGDecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
 
   return mLexer.Lex(aIterator, aOnResume,
                     [=](State aState, const char* aData, size_t aLength) {
     switch (aState) {
       case State::PNG_DATA:
--- a/image/decoders/nsPNGDecoder.h
+++ b/image/decoders/nsPNGDecoder.h
@@ -18,18 +18,18 @@ namespace image {
 class RasterImage;
 
 class nsPNGDecoder : public Decoder
 {
 public:
   virtual ~nsPNGDecoder();
 
   nsresult InitInternal() override;
-  Maybe<TerminalState> DoDecode(SourceBufferIterator& aIterator,
-                                IResumable* aOnResume) override;
+  LexerResult DoDecode(SourceBufferIterator& aIterator,
+                       IResumable* aOnResume) override;
   virtual Telemetry::ID SpeedHistogram() override;
 
   /// @return true if this PNG is a valid ICO resource.
   bool IsValidICO() const;
 
 private:
   friend class DecoderFactory;
 
--- a/image/test/gtest/TestStreamingLexer.cpp
+++ b/image/test/gtest/TestStreamingLexer.cpp
@@ -145,241 +145,246 @@ protected:
   RefPtr<CountResumes> mCountResumes;
 };
 
 TEST_F(ImageStreamingLexer, ZeroLengthData)
 {
   // Test a zero-length input.
   mSourceBuffer->Complete(NS_OK);
 
-  Maybe<TerminalState> result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);
+  LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);
 
-  EXPECT_TRUE(result.isSome());
-  EXPECT_EQ(Some(TerminalState::FAILURE), result);
+  EXPECT_TRUE(result.is<TerminalState>());
+  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
 }
 
 TEST_F(ImageStreamingLexer, SingleChunk)
 {
   // Test delivering all the data at once.
   mSourceBuffer->Append(mData, sizeof(mData));
   mSourceBuffer->Complete(NS_OK);
 
-  Maybe<TerminalState> result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);
+  LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);
 
-  EXPECT_TRUE(result.isSome());
-  EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+  EXPECT_TRUE(result.is<TerminalState>());
+  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
 }
 
 TEST_F(ImageStreamingLexer, SingleChunkWithUnbuffered)
 {
   Vector<char> unbufferedVector;
 
   // Test delivering all the data at once.
   mSourceBuffer->Append(mData, sizeof(mData));
   mSourceBuffer->Complete(NS_OK);
 
-  Maybe<TerminalState> result =
+  LexerResult result =
     mLexer.Lex(mIterator, mExpectNoResume,
                [&](TestState aState, const char* aData, size_t aLength) {
       return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
   });
 
-  EXPECT_TRUE(result.isSome());
-  EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+  EXPECT_TRUE(result.is<TerminalState>());
+  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
 }
 
 TEST_F(ImageStreamingLexer, ChunkPerState)
 {
   // Test delivering in perfectly-sized chunks, one per state.
   for (unsigned i = 0; i < 3; ++i) {
     mSourceBuffer->Append(mData + 3 * i, 3);
-    Maybe<TerminalState> result = mLexer.Lex(mIterator, mCountResumes, DoLex);
+    LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLex);
 
     if (i == 2) {
-      EXPECT_TRUE(result.isSome());
-      EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+      EXPECT_TRUE(result.is<TerminalState>());
+      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
     } else {
-      EXPECT_TRUE(result.isNothing());
+      EXPECT_TRUE(result.is<Yield>());
+      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
     }
   }
 
   EXPECT_EQ(2u, mCountResumes->Count());
   mSourceBuffer->Complete(NS_OK);
 }
 
 TEST_F(ImageStreamingLexer, ChunkPerStateWithUnbuffered)
 {
   Vector<char> unbufferedVector;
 
   // Test delivering in perfectly-sized chunks, one per state.
   for (unsigned i = 0; i < 3; ++i) {
     mSourceBuffer->Append(mData + 3 * i, 3);
-    Maybe<TerminalState> result =
+    LexerResult result =
       mLexer.Lex(mIterator, mCountResumes,
                  [&](TestState aState, const char* aData, size_t aLength) {
         return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
     });
 
     if (i == 2) {
-      EXPECT_TRUE(result.isSome());
-      EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+      EXPECT_TRUE(result.is<TerminalState>());
+      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
     } else {
-      EXPECT_TRUE(result.isNothing());
+      EXPECT_TRUE(result.is<Yield>());
+      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
     }
   }
 
   EXPECT_EQ(2u, mCountResumes->Count());
   mSourceBuffer->Complete(NS_OK);
 }
 
 TEST_F(ImageStreamingLexer, OneByteChunks)
 {
   // Test delivering in one byte chunks.
   for (unsigned i = 0; i < 9; ++i) {
     mSourceBuffer->Append(mData + i, 1);
-    Maybe<TerminalState> result = mLexer.Lex(mIterator, mCountResumes, DoLex);
+    LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLex);
 
     if (i == 8) {
-      EXPECT_TRUE(result.isSome());
-      EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+      EXPECT_TRUE(result.is<TerminalState>());
+      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
     } else {
-      EXPECT_TRUE(result.isNothing());
+      EXPECT_TRUE(result.is<Yield>());
+      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
     }
   }
 
   EXPECT_EQ(8u, mCountResumes->Count());
   mSourceBuffer->Complete(NS_OK);
 }
 
 TEST_F(ImageStreamingLexer, OneByteChunksWithUnbuffered)
 {
   Vector<char> unbufferedVector;
 
   // Test delivering in one byte chunks.
   for (unsigned i = 0; i < 9; ++i) {
     mSourceBuffer->Append(mData + i, 1);
-    Maybe<TerminalState> result =
+    LexerResult result =
       mLexer.Lex(mIterator, mCountResumes,
                  [&](TestState aState, const char* aData, size_t aLength) {
         return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
     });
 
     if (i == 8) {
-      EXPECT_TRUE(result.isSome());
-      EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+      EXPECT_TRUE(result.is<TerminalState>());
+      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
     } else {
-      EXPECT_TRUE(result.isNothing());
+      EXPECT_TRUE(result.is<Yield>());
+      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
     }
   }
 
   EXPECT_EQ(8u, mCountResumes->Count());
   mSourceBuffer->Complete(NS_OK);
 }
 
 TEST_F(ImageStreamingLexer, ZeroLengthState)
 {
   mSourceBuffer->Append(mData, sizeof(mData));
   mSourceBuffer->Complete(NS_OK);
 
   // Create a special StreamingLexer for this test because we want the first
   // state to be zero length.
   StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 0));
 
-  Maybe<TerminalState> result =
+  LexerResult result =
     lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthStates);
 
-  EXPECT_TRUE(result.isSome());
-  EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+  EXPECT_TRUE(result.is<TerminalState>());
+  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
 }
 
 TEST_F(ImageStreamingLexer, ZeroLengthStateWithUnbuffered)
 {
   mSourceBuffer->Append(mData, sizeof(mData));
   mSourceBuffer->Complete(NS_OK);
 
   // Create a special StreamingLexer for this test because we want the first
   // state to be both zero length and unbuffered.
   StreamingLexer<TestState> lexer(Transition::ToUnbuffered(TestState::ONE,
                                                            TestState::UNBUFFERED,
                                                            0));
 
-  Maybe<TerminalState> result =
+  LexerResult result =
     lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthStatesUnbuffered);
 
-  EXPECT_TRUE(result.isSome());
-  EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+  EXPECT_TRUE(result.is<TerminalState>());
+  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
 }
 
 TEST_F(ImageStreamingLexer, TerminateSuccess)
 {
   mSourceBuffer->Append(mData, sizeof(mData));
   mSourceBuffer->Complete(NS_OK);
 
   // Test that Terminate is "sticky".
   SourceBufferIterator iterator = mSourceBuffer->Iterator();
-  Maybe<TerminalState> result =
+  LexerResult result =
     mLexer.Lex(iterator, mExpectNoResume,
                [&](TestState aState, const char* aData, size_t aLength) {
       EXPECT_TRUE(aState == TestState::ONE);
       return Transition::TerminateSuccess();
   });
-  EXPECT_TRUE(result.isSome());
-  EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+  EXPECT_TRUE(result.is<TerminalState>());
+  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
 
   SourceBufferIterator iterator2 = mSourceBuffer->Iterator();
   result =
     mLexer.Lex(iterator2, mExpectNoResume,
                [&](TestState aState, const char* aData, size_t aLength) {
       EXPECT_TRUE(false);  // Shouldn't get here.
       return Transition::TerminateFailure();
   });
-  EXPECT_TRUE(result.isSome());
-  EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+  EXPECT_TRUE(result.is<TerminalState>());
+  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
 }
 
 TEST_F(ImageStreamingLexer, TerminateFailure)
 {
   mSourceBuffer->Append(mData, sizeof(mData));
   mSourceBuffer->Complete(NS_OK);
 
   // Test that Terminate is "sticky".
   SourceBufferIterator iterator = mSourceBuffer->Iterator();
-  Maybe<TerminalState> result =
+  LexerResult result =
     mLexer.Lex(iterator, mExpectNoResume,
                [&](TestState aState, const char* aData, size_t aLength) {
       EXPECT_TRUE(aState == TestState::ONE);
       return Transition::TerminateFailure();
   });
-  EXPECT_TRUE(result.isSome());
-  EXPECT_EQ(Some(TerminalState::FAILURE), result);
+  EXPECT_TRUE(result.is<TerminalState>());
+  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
 
   SourceBufferIterator iterator2 = mSourceBuffer->Iterator();
   result =
     mLexer.Lex(iterator2, mExpectNoResume,
                [&](TestState aState, const char* aData, size_t aLength) {
       EXPECT_TRUE(false);  // Shouldn't get here.
       return Transition::TerminateFailure();
   });
-  EXPECT_TRUE(result.isSome());
-  EXPECT_EQ(Some(TerminalState::FAILURE), result);
+  EXPECT_TRUE(result.is<TerminalState>());
+  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
 }
 
 TEST_F(ImageStreamingLexer, TerminateUnbuffered)
 {
   // Test that Terminate works during an unbuffered read.
   for (unsigned i = 0; i < 9; ++i) {
     mSourceBuffer->Append(mData + i, 1);
-    Maybe<TerminalState> result =
+    LexerResult result =
       mLexer.Lex(mIterator, mCountResumes, DoLexWithUnbufferedTerminate);
 
     if (i > 2) {
-      EXPECT_TRUE(result.isSome());
-      EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+      EXPECT_TRUE(result.is<TerminalState>());
+      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
     } else {
-      EXPECT_TRUE(result.isNothing());
+      EXPECT_TRUE(result.is<Yield>());
+      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
     }
   }
 
   // We expect 3 resumes because TestState::ONE consumes 3 bytes and then
   // transitions to TestState::UNBUFFERED, which calls TerminateSuccess() as
   // soon as it receives a single byte. That's four bytes total,  which are
   // delivered one at a time, requiring 3 resumes.
   EXPECT_EQ(3u, mCountResumes->Count());
@@ -389,40 +394,41 @@ TEST_F(ImageStreamingLexer, TerminateUnb
 
 TEST_F(ImageStreamingLexer, SourceBufferImmediateComplete)
 {
   // Test calling SourceBuffer::Complete() without appending any data. This
   // causes the SourceBuffer to automatically have a failing completion status,
   // no matter what you pass, so we expect TerminalState::FAILURE below.
   mSourceBuffer->Complete(NS_OK);
 
-  Maybe<TerminalState> result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);
+  LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);
 
-  EXPECT_TRUE(result.isSome());
-  EXPECT_EQ(Some(TerminalState::FAILURE), result);
+  EXPECT_TRUE(result.is<TerminalState>());
+  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
 }
 
 TEST_F(ImageStreamingLexer, SourceBufferTruncatedSuccess)
 {
   // Test that calling SourceBuffer::Complete() with a successful status results
   // in an immediate TerminalState::SUCCESS result.
   for (unsigned i = 0; i < 9; ++i) {
     if (i < 2) {
       mSourceBuffer->Append(mData + i, 1);
     } else if (i == 2) {
       mSourceBuffer->Complete(NS_OK);
     }
 
-    Maybe<TerminalState> result = mLexer.Lex(mIterator, mCountResumes, DoLex);
+    LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLex);
 
     if (i >= 2) {
-      EXPECT_TRUE(result.isSome());
-      EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+      EXPECT_TRUE(result.is<TerminalState>());
+      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
     } else {
-      EXPECT_TRUE(result.isNothing());
+      EXPECT_TRUE(result.is<Yield>());
+      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
     }
   }
 
   EXPECT_EQ(2u, mCountResumes->Count());
 }
 
 TEST_F(ImageStreamingLexer, SourceBufferTruncatedFailure)
 {
@@ -430,38 +436,40 @@ TEST_F(ImageStreamingLexer, SourceBuffer
   // an immediate TerminalState::FAILURE result.
   for (unsigned i = 0; i < 9; ++i) {
     if (i < 2) {
       mSourceBuffer->Append(mData + i, 1);
     } else if (i == 2) {
       mSourceBuffer->Complete(NS_ERROR_FAILURE);
     }
 
-    Maybe<TerminalState> result = mLexer.Lex(mIterator, mCountResumes, DoLex);
+    LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLex);
 
     if (i >= 2) {
-      EXPECT_TRUE(result.isSome());
-      EXPECT_EQ(Some(TerminalState::FAILURE), result);
+      EXPECT_TRUE(result.is<TerminalState>());
+      EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
     } else {
-      EXPECT_TRUE(result.isNothing());
+      EXPECT_TRUE(result.is<Yield>());
+      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
     }
   }
 
   EXPECT_EQ(2u, mCountResumes->Count());
 }
 
 TEST_F(ImageStreamingLexer, NoSourceBufferResumable)
 {
   // Test delivering in one byte chunks with no IResumable.
   for (unsigned i = 0; i < 9; ++i) {
     mSourceBuffer->Append(mData + i, 1);
-    Maybe<TerminalState> result = mLexer.Lex(mIterator, nullptr, DoLex);
+    LexerResult result = mLexer.Lex(mIterator, nullptr, DoLex);
 
     if (i == 8) {
-      EXPECT_TRUE(result.isSome());
-      EXPECT_EQ(Some(TerminalState::SUCCESS), result);
+      EXPECT_TRUE(result.is<TerminalState>());
+      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
     } else {
-      EXPECT_TRUE(result.isNothing());
+      EXPECT_TRUE(result.is<Yield>());
+      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
     }
   }
 
   mSourceBuffer->Complete(NS_OK);
 }