Support for Any (#116)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 21d492b..b605451 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.10.1
+
+* Added Support for [any](https://developers.google.com/protocol-buffers/docs/proto3#any) messages.
+
 ## 0.10.0
 
 * Breaking change: Add `GeneratedMessage.freeze()`. A frozen message and its
diff --git a/lib/protobuf.dart b/lib/protobuf.dart
index dd08da7..177a717 100644
--- a/lib/protobuf.dart
+++ b/lib/protobuf.dart
@@ -35,6 +35,7 @@
 part 'src/protobuf/rpc_client.dart';
 part 'src/protobuf/unknown_field_set.dart';
 part 'src/protobuf/utils.dart';
+part 'src/protobuf/unpack.dart';
 part 'src/protobuf/wire_format.dart';
 
 // TODO(sra): Remove this method when clients upgrade to protoc 0.3.5
diff --git a/lib/src/protobuf/builder_info.dart b/lib/src/protobuf/builder_info.dart
index abc0965..0670c56 100644
--- a/lib/src/protobuf/builder_info.dart
+++ b/lib/src/protobuf/builder_info.dart
@@ -6,6 +6,7 @@
 
 /// Per-message type setup.
 class BuilderInfo {
+  /// The fully qualified name of this message.
   final String messageName;
   final List<FieldInfo> byIndex = <FieldInfo>[];
   final Map<int, FieldInfo> fieldInfo = new Map<int, FieldInfo>();
@@ -15,7 +16,8 @@
   bool hasRequiredFields = true;
   List<FieldInfo> _sortedByTag;
 
-  BuilderInfo(this.messageName);
+  BuilderInfo(String messageName, {PackageName package = const PackageName('')})
+      : messageName = "${package.prefix}$messageName";
 
   void add<T>(
       int tagNumber,
diff --git a/lib/src/protobuf/exceptions.dart b/lib/src/protobuf/exceptions.dart
index 412a8d8..bc8d43c 100644
--- a/lib/src/protobuf/exceptions.dart
+++ b/lib/src/protobuf/exceptions.dart
@@ -34,4 +34,11 @@
 input has been truncated or that an embedded message
 misreported its own length.
 ''');
+
+  InvalidProtocolBufferException.wrongAnyMessage(
+      String anyTypeName, unpackerTypeName)
+      : this._('''
+The type of the Any message ($anyTypeName) does not match the given
+unpacker ($unpackerTypeName).
+''');
 }
diff --git a/lib/src/protobuf/generated_message.dart b/lib/src/protobuf/generated_message.dart
index fb22b2d..0adc6c9 100644
--- a/lib/src/protobuf/generated_message.dart
+++ b/lib/src/protobuf/generated_message.dart
@@ -373,3 +373,10 @@
   /// For generated code only.
   void $_setInt64(int index, Int64 value) => _fieldSet._$set(index, value);
 }
+
+/// The package name of a protobuf message.
+class PackageName {
+  final String name;
+  const PackageName(this.name);
+  String get prefix => name == '' ? '' : '$name.';
+}
diff --git a/lib/src/protobuf/unpack.dart b/lib/src/protobuf/unpack.dart
new file mode 100644
index 0000000..142ebcd
--- /dev/null
+++ b/lib/src/protobuf/unpack.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of protobuf;
+
+/// Unpacks the message in [value] into [instance].
+///
+/// Throws a [InvalidProtocolBufferException] if [typeUrl] does not correspond
+/// with the type of [instance].
+///
+/// This is a helper method for `Any.unpackInto`.
+void unpackIntoHelper<T extends GeneratedMessage>(
+    List<int> value, T instance, String typeUrl,
+    {ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY}) {
+  // From "google/protobuf/any.proto":
+  //
+  //   The pack methods provided by protobuf library will by default use
+  //   'type.googleapis.com/full.type.name' as the type URL and the unpack
+  //   methods only use the fully qualified type name after the last '/'
+  //   in the type URL, for example "foo.bar.com/x/y.z" will yield type
+  //   name "y.z".
+  if (!canUnpackIntoHelper(instance, typeUrl)) {
+    String typeName = instance.info_.messageName;
+    throw new InvalidProtocolBufferException.wrongAnyMessage(
+        _typeNameFromUrl(typeUrl), typeName);
+  }
+  instance.mergeFromBuffer(value, extensionRegistry);
+}
+
+/// Returns `true` if the type of [instance] is described by
+/// `typeUrl`.
+///
+/// This is a helper method for `Any.canUnpackInto`.
+bool canUnpackIntoHelper(GeneratedMessage instance, String typeUrl) {
+  return instance.info_.messageName == _typeNameFromUrl(typeUrl);
+}
+
+String _typeNameFromUrl(String typeUrl) {
+  int index = typeUrl.lastIndexOf('/');
+  return index == -1 ? '' : typeUrl.substring(index + 1);
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index c715c6b..fb08c89 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: protobuf
-version: 0.10.0
+version: 0.10.1
 author: Dart Team <misc@dartlang.org>
 description: Runtime library for protocol buffers support.
 homepage: https://github.com/dart-lang/protobuf