made RawQueue options type-safe
diff --git a/aos/linux_code/ipc_lib/queue.h b/aos/linux_code/ipc_lib/queue.h
index 5edce62..31e8075 100644
--- a/aos/linux_code/ipc_lib/queue.h
+++ b/aos/linux_code/ipc_lib/queue.h
@@ -6,6 +6,8 @@
 #include "aos/linux_code/ipc_lib/shared_mem.h"
 #include "aos/common/mutex.h"
 #include "aos/common/condition.h"
+#include "aos/common/util/options.h"
+#include "aos/common/logging/logging.h"
 
 // TODO(brians) add valgrind client requests to the queue and shared_mem_malloc
 // code to make checking for leaks work better
@@ -56,38 +58,45 @@
                       int recycle_hash, int recycle_queue_length,
                       RawQueue **recycle);
 
-  // Constants for passing to options arguments.
-  // The non-conflicting ones can be combined with bitwise-or.
-
   // Doesn't update the currently read index (the read messages in the queue or
   // the index). This means the returned message (and any others skipped with
   // kFromEnd) will be left in the queue.
   // For reading only.
-  static const int kPeek = 0x0001;
+  // Not valid for ReadMessageIndex combined with kFromEnd.
+  static constexpr Options<RawQueue>::Option kPeek{0x0001};
   // Reads the last message in the queue instead of just the next one.
   // NOTE: This removes all of the messages until the last one from the queue
   // (which means that nobody else will read them).
   // For reading only.
-  static const int kFromEnd = 0x0002;
+  // Not valid for ReadMessageIndex combined with kPeek.
+  static constexpr Options<RawQueue>::Option kFromEnd{0x0002};
   // Causes reads to return NULL and writes to fail instead of waiting.
   // For reading and writing.
-  static const int kNonBlock = 0x0004;
+  static constexpr Options<RawQueue>::Option kNonBlock{0x0004};
   // Causes things to block.
-  // IMPORTANT: Has a value of 0 so that it is the default. This has to stay
-  // this way.
   // For reading and writing.
-  static const int kBlock = 0x0000;
+  static constexpr Options<RawQueue>::Option kBlock{0x0008};
   // Causes writes to overwrite the oldest message in the queue instead of
   // blocking.
   // For writing only.
-  static const int kOverride = 0x0008;
+  static constexpr Options<RawQueue>::Option kOverride{0x0010};
 
   // Writes a message into the queue.
   // This function takes ownership of msg.
   // NOTE: msg must point to a valid message from this queue
   // Returns true on success. A return value of false means msg has already been
   // freed.
-  bool WriteMessage(void *msg, int options);
+  bool WriteMessage(void *msg, Options<RawQueue> options) {
+    static constexpr Options<RawQueue> kWriteFailureOptions =
+        kNonBlock | kBlock | kOverride;
+    if (!options.NoOthersSet(kWriteFailureOptions)) {
+      LOG(FATAL, "illegal write options in %x\n", options.printable());
+    }
+    if (!options.ExactlyOneSet(kWriteFailureOptions)) {
+      LOG(FATAL, "invalid write options %x\n", options.printable());
+    }
+    return DoWriteMessage(msg, options);
+  }
 
   // Reads a message out of the queue.
   // The return value will have at least the length of this queue's worth of
@@ -96,13 +105,26 @@
   // messsage. Do not cast the const away!
   // IMPORTANT: The return value (if not NULL) must eventually be passed to
   // FreeMessage.
-  const void *ReadMessage(int options);
+  const void *ReadMessage(Options<RawQueue> options) {
+    CheckReadOptions(options);
+    return DoReadMessage(options);
+  }
   // The same as ReadMessage, except it will never return the
   // same message twice (when used with the same index argument). However,
   // may not return some messages that pass through the queue.
   // *index should start as 0. index does not have to be in shared memory, but
   // it can be.
-  const void *ReadMessageIndex(int options, int *index);
+  // Calling with both kPeek and kFromEnd in options isn't valid because that
+  // would mean ignoring index, which would make this function the same as
+  // ReadMessage (which should be used instead).
+  const void *ReadMessageIndex(Options<RawQueue> options, int *index) {
+    CheckReadOptions(options);
+    static constexpr Options<RawQueue> kFromEndAndPeek = kFromEnd | kPeek;
+    if (options.AllSet(kFromEndAndPeek)) {
+      LOG(FATAL, "ReadMessageIndex(kFromEnd | kPeek) is not allowed\n");
+    }
+    return DoReadMessageIndex(options, index);
+  }
 
   // Retrieves ("allocates") a message that can then be written to the queue.
   // NOTE: the return value will be completely uninitialized
@@ -125,6 +147,22 @@
  private:
   struct MessageHeader;
 
+  // The public wrappers around these are inlined and do argument checking.
+  bool DoWriteMessage(void *msg, Options<RawQueue> options);
+  const void *DoReadMessage(Options<RawQueue> options);
+  const void *DoReadMessageIndex(Options<RawQueue> options, int *index);
+  void CheckReadOptions(Options<RawQueue> options) {
+    static constexpr Options<RawQueue> kValidOptions =
+        kPeek | kFromEnd | kNonBlock | kBlock;
+    if (!options.NoOthersSet(kValidOptions)) {
+      LOG(FATAL, "illegal read options in %x\n", options.printable());
+    }
+    static constexpr Options<RawQueue> kBlockChoices = kNonBlock | kBlock;
+    if (!options.ExactlyOneSet(kBlockChoices)) {
+      LOG(FATAL, "invalid read options %x\n", options.printable());
+    }
+  }
+
   // Adds 1 to the given index and handles wrapping correctly.
   int index_add1(int index);
 
@@ -175,7 +213,7 @@
   // Must be called with data_lock_ locked.
   // *read_data will be initialized.
   // Returns with a readable message in data_ or false.
-  bool ReadCommonStart(int options, int *index);
+  bool ReadCommonStart(Options<RawQueue> options, int *index);
   // Deals with setting/unsetting readable_ and writable_.
   // Must be called after data_lock_ has been unlocked.
   // read_data should be the same thing that was passed in to ReadCommonStart.