void VariableSerializer::writeArrayKey(const ArrayData *arr, Variant key) {
  if (m_type == APCSerialize && key.isString()) {
    write(key.toString());
    return;
  }
  ArrayInfo &info = m_arrayInfos.back();
  const ClassInfo *cls = info.class_info;
  if (info.is_object) {
    String ks(key.toString());
    if (ks.size() > 0 && ks.charAt(0) == '\0') {
      // fast path for serializing private properties
      if (m_type == Serialize) {
        write(ks);
        return;
      }
      int span = ks.find('\0', 1);
      ASSERT(span != String::npos);
      String cl(ks.substr(1, span - 1));
      cls = ClassInfo::FindClass(cl);
      ASSERT(cls);
      key = ks.substr(span + 1);
    }
  }
  switch (m_type) {
  case PrintR: {
    indent();
    m_buf->append('[');
      String keyStr = key.toString();
      const char *p = keyStr;
      int len = keyStr.length();
      m_buf->append(p, len);
      if (info.is_object) writePropertyPrivacy(keyStr, cls);
      m_buf->append("] => ");
    break;
  }
  case VarExport:
    indent();
    write(key, true);
    m_buf->append(" => ");
    break;
  case VarDump:
  case DebugDump:
    indent();
    if (key.isNumeric()) {
      m_buf->append('[');
      m_buf->append((const char *)key.toString());
      m_buf->append("]=>\n");
    } else {
      m_buf->append("[\"");
      String keyStr = key.toString();
      const char *p = keyStr;
      int len = keyStr.length();
      m_buf->append(p, len);
      if (info.is_object) writePropertyPrivacy(keyStr, cls);
      m_buf->append("\"]=>\n");
    }
    break;
  case Serialize:
  case APCSerialize:
  case DebuggerSerialize:
    if (info.is_object) {
      writeSerializedProperty(key.toString(), cls);
    } else {
      write(key);
    }
    break;
  case JSON:
  case DebuggerDump:
    if (!info.first_element) {
      m_buf->append(',');
    }
    if (!info.is_vector) {
      write(key.toString());
      m_buf->append(':');
    }
    break;
  default:
    ASSERT(false);
    break;
  }
}
void VariableSerializer::writeArrayKey(const ArrayData *arr, Variant key) {
  ArrayInfo &info = m_arrayInfos.back();
  const ClassInfo *cls = info.class_info;
  if (info.is_object) {
    String ks(key.toString());
    if (ks.charAt(0) == '\0') {
      int span = ks.find('\0', 1);
      ASSERT(span != String::npos);
      String cl(ks.substr(1, span - 1));
      cls = ClassInfo::FindClass(cl);
      ASSERT(cls);
      key = ks.substr(span + 1);
    }
  }
  switch (m_type) {
  case PrintR: {
    indent();
    *m_out << '[';
      String keyStr = key.toString();
      const char *p = keyStr;
      int len  = keyStr.length();
      for (int i = 0; i < len; i++) {
        *m_out << *p++;
      }
      if (info.is_object) writePropertyPrivacy(keyStr.c_str(), cls);
      *m_out << "] => ";
    break;
  }
  case VarExport:
    indent();
    write(key, true);
    *m_out << " => ";
    break;
  case VarDump:
  case DebugDump:
    indent();
    if (key.isNumeric()) {
      *m_out << '[' << (const char *)key.toString() << "]=>\n";
    } else {
      *m_out << "[\"";
      String keyStr = key.toString();
      const char *p = keyStr;
      int len  = keyStr.length();
      for (int i = 0; i < len; i++) {
        *m_out << *p++;
      }
      if (info.is_object) writePropertyPrivacy(keyStr.c_str(), cls);
      *m_out << "\"]=>\n";
    }
    break;
  case Serialize:
    if (info.is_object) {
      writeSerializedProperty(key.toString(), cls);
    } else {
      write(key);
    }
    break;
  case JSON:
    if (!info.first_element) {
      *m_out << ",";
    }
    if (!info.is_vector) {
      write(key.toString());
      *m_out << ":";
    }
    break;
  default:
    ASSERT(false);
    break;
  }
}