blob: 8f2717c5ba7a9d0ad40bfcb0ffc464ce377746a8 [file] [log] [blame]
Jon Skeetee835a32015-06-30 17:22:26 +01001#region Copyright notice and license
2// Protocol Buffers - Google's data interchange format
3// Copyright 2015 Google Inc. All rights reserved.
4// https://developers.google.com/protocol-buffers/
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31#endregion
32
33using System;
Jon Skeete38294a2015-06-09 19:30:44 +010034using System.IO;
Jon Skeete38294a2015-06-09 19:30:44 +010035
36namespace Google.Protobuf
37{
Jon Skeetcdeda4b2015-06-19 17:30:13 +010038 /// <summary>
39 /// A parser for a specific message type.
40 /// </summary>
41 /// <remarks>
42 /// <p>
43 /// This delegates most behavior to the
44 /// <see cref="IMessage.MergeFrom"/> implementation within the original type, but
45 /// provides convenient overloads to parse from a variety of sources.
46 /// </p>
47 /// <p>
48 /// Most applications will never need to create their own instances of this type;
49 /// instead, use the static <c>Parser</c> property of a generated message type to obtain a
50 /// parser for that type.
51 /// </p>
52 /// </remarks>
53 /// <typeparam name="T">The type of message to be parsed.</typeparam>
Jon Skeete38294a2015-06-09 19:30:44 +010054 public sealed class MessageParser<T> where T : IMessage<T>
55 {
56 private readonly Func<T> factory;
57
Jon Skeetcdeda4b2015-06-19 17:30:13 +010058 /// <summary>
59 /// Creates a new parser.
60 /// </summary>
61 /// <remarks>
62 /// The factory method is effectively an optimization over using a generic constraint
63 /// to require a parameterless constructor: delegates are significantly faster to execute.
64 /// </remarks>
65 /// <param name="factory">Function to invoke when a new, empty message is required.</param>
Jon Skeete38294a2015-06-09 19:30:44 +010066 public MessageParser(Func<T> factory)
67 {
68 this.factory = factory;
69 }
70
Jon Skeetcdeda4b2015-06-19 17:30:13 +010071 /// <summary>
72 /// Creates a template instance ready for population.
73 /// </summary>
74 /// <returns>An empty message.</returns>
Jon Skeete38294a2015-06-09 19:30:44 +010075 internal T CreateTemplate()
76 {
77 return factory();
78 }
79
Jon Skeetcdeda4b2015-06-19 17:30:13 +010080 /// <summary>
81 /// Parses a message from a byte array.
82 /// </summary>
83 /// <param name="data">The byte array containing the message. Must not be null.</param>
84 /// <returns>The newly parsed message.</returns>
Jon Skeete38294a2015-06-09 19:30:44 +010085 public T ParseFrom(byte[] data)
86 {
Jon Skeet68380f02015-07-30 13:03:45 +010087 Preconditions.CheckNotNull(data, "data");
Jon Skeete38294a2015-06-09 19:30:44 +010088 T message = factory();
89 message.MergeFrom(data);
90 return message;
91 }
92
Jon Skeet811fc892015-08-04 15:58:39 +010093 /// <summary>
94 /// Parses a message from the given byte string.
95 /// </summary>
96 /// <param name="data">The data to parse.</param>
97 /// <returns>The parsed message.</returns>
Jon Skeete38294a2015-06-09 19:30:44 +010098 public T ParseFrom(ByteString data)
99 {
Jon Skeet68380f02015-07-30 13:03:45 +0100100 Preconditions.CheckNotNull(data, "data");
Jon Skeete38294a2015-06-09 19:30:44 +0100101 T message = factory();
102 message.MergeFrom(data);
103 return message;
104 }
105
Jon Skeet811fc892015-08-04 15:58:39 +0100106 /// <summary>
107 /// Parses a message from the given stream.
108 /// </summary>
109 /// <param name="input">The stream to parse.</param>
110 /// <returns>The parsed message.</returns>
Jon Skeete38294a2015-06-09 19:30:44 +0100111 public T ParseFrom(Stream input)
112 {
113 T message = factory();
114 message.MergeFrom(input);
115 return message;
116 }
117
Jon Skeet811fc892015-08-04 15:58:39 +0100118 /// <summary>
119 /// Parses a length-delimited message from the given stream.
120 /// </summary>
121 /// <remarks>
122 /// The stream is expected to contain a length and then the data. Only the amount of data
123 /// specified by the length will be consumed.
124 /// </remarks>
125 /// <param name="input">The stream to parse.</param>
126 /// <returns>The parsed message.</returns>
Jon Skeete38294a2015-06-09 19:30:44 +0100127 public T ParseDelimitedFrom(Stream input)
128 {
129 T message = factory();
130 message.MergeDelimitedFrom(input);
131 return message;
132 }
133
Jon Skeet811fc892015-08-04 15:58:39 +0100134 /// <summary>
135 /// Parses a message from the given coded input stream.
136 /// </summary>
137 /// <param name="input">The stream to parse.</param>
138 /// <returns>The parsed message.</returns>
Jon Skeet96ddf012015-06-12 09:53:12 +0100139 public T ParseFrom(CodedInputStream input)
Jon Skeete38294a2015-06-09 19:30:44 +0100140 {
141 T message = factory();
142 message.MergeFrom(input);
143 return message;
144 }
Jon Skeetfb248822015-09-04 12:41:14 +0100145
146 /// <summary>
147 /// Parses a message from the given JSON.
148 /// </summary>
149 /// <param name="json">The JSON to parse.</param>
150 /// <returns>The parsed message.</returns>
Jon Skeet0fb39c42015-11-04 11:49:15 +0000151 /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
152 /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
Jon Skeetfb248822015-09-04 12:41:14 +0100153 public T ParseJson(string json)
154 {
155 T message = factory();
156 JsonParser.Default.Merge(message, json);
157 return message;
158 }
Jon Skeete38294a2015-06-09 19:30:44 +0100159 }
160}