LazyBsonArray.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /* Copyright 2010-2015 MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.IO;
  19. using MongoDB.Bson.IO;
  20. using MongoDB.Bson.Serialization;
  21. using MongoDB.Bson.Serialization.Attributes;
  22. using MongoDB.Bson.Serialization.Serializers;
  23. namespace MongoDB.Bson
  24. {
  25. /// <summary>
  26. /// Represents a BSON array that is deserialized lazily.
  27. /// </summary>
  28. [BsonSerializer(typeof(LazyBsonArraySerializer))]
  29. public class LazyBsonArray : MaterializedOnDemandBsonArray
  30. {
  31. // private fields
  32. private IByteBuffer _slice;
  33. private List<IDisposable> _disposableItems = new List<IDisposable>();
  34. private BsonBinaryReaderSettings _readerSettings = BsonBinaryReaderSettings.Defaults;
  35. // constructors
  36. /// <summary>
  37. /// Initializes a new instance of the <see cref="LazyBsonArray"/> class.
  38. /// </summary>
  39. /// <param name="slice">The slice.</param>
  40. /// <exception cref="System.ArgumentNullException">slice</exception>
  41. /// <exception cref="System.ArgumentException">LazyBsonArray cannot be used with an IByteBuffer that needs disposing.</exception>
  42. public LazyBsonArray(IByteBuffer slice)
  43. {
  44. if (slice == null)
  45. {
  46. throw new ArgumentNullException("slice");
  47. }
  48. _slice = slice;
  49. }
  50. // public properties
  51. /// <summary>
  52. /// Gets the slice.
  53. /// </summary>
  54. /// <value>
  55. /// The slice.
  56. /// </value>
  57. public IByteBuffer Slice
  58. {
  59. get { return _slice; }
  60. }
  61. /// <summary>
  62. /// Creates a shallow clone of the array (see also DeepClone).
  63. /// </summary>
  64. /// <returns>A shallow clone of the array.</returns>
  65. public override BsonValue Clone()
  66. {
  67. if (_slice != null)
  68. {
  69. return new LazyBsonArray(CloneSlice());
  70. }
  71. else
  72. {
  73. return base.Clone();
  74. }
  75. }
  76. /// <summary>
  77. /// Creates a deep clone of the array (see also Clone).
  78. /// </summary>
  79. /// <returns>A deep clone of the array.</returns>
  80. public override BsonValue DeepClone()
  81. {
  82. if (_slice != null)
  83. {
  84. return new LazyBsonArray(CloneSlice());
  85. }
  86. else
  87. {
  88. return base.Clone();
  89. }
  90. }
  91. // protected methods
  92. /// <summary>
  93. /// Releases unmanaged and - optionally - managed resources.
  94. /// </summary>
  95. /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  96. protected override void Dispose(bool disposing)
  97. {
  98. if (!IsDisposed)
  99. {
  100. if (disposing)
  101. {
  102. if (_slice != null)
  103. {
  104. _slice.Dispose();
  105. _slice = null;
  106. }
  107. if (_disposableItems != null)
  108. {
  109. _disposableItems.ForEach(x => x.Dispose());
  110. _disposableItems = null;
  111. }
  112. }
  113. }
  114. base.Dispose(disposing);
  115. }
  116. /// <summary>
  117. /// Materializes the BsonArray.
  118. /// </summary>
  119. /// <returns>
  120. /// The materialized values.
  121. /// </returns>
  122. protected override IEnumerable<BsonValue> Materialize()
  123. {
  124. return MaterializeThisLevel();
  125. }
  126. /// <summary>
  127. /// Informs subclasses that the Materialize process completed so they can free any resources related to the unmaterialized state.
  128. /// </summary>
  129. protected override void MaterializeCompleted()
  130. {
  131. var slice = _slice;
  132. _slice = null;
  133. slice.Dispose();
  134. }
  135. // private methods
  136. private IByteBuffer CloneSlice()
  137. {
  138. return _slice.GetSlice(0, _slice.Length);
  139. }
  140. private LazyBsonArray DeserializeLazyBsonArray(BsonBinaryReader bsonReader)
  141. {
  142. var slice = bsonReader.ReadRawBsonArray();
  143. var nestedArray = new LazyBsonArray(slice);
  144. _disposableItems.Add(nestedArray);
  145. return nestedArray;
  146. }
  147. private LazyBsonDocument DeserializeLazyBsonDocument(BsonBinaryReader bsonReader)
  148. {
  149. var slice = bsonReader.ReadRawBsonDocument();
  150. var nestedDocument = new LazyBsonDocument(slice);
  151. _disposableItems.Add(nestedDocument);
  152. return nestedDocument;
  153. }
  154. private IEnumerable<BsonValue> MaterializeThisLevel()
  155. {
  156. var values = new List<BsonValue>();
  157. using (var stream = new ByteBufferStream(_slice, ownsBuffer: false))
  158. using (var bsonReader = new BsonBinaryReader(stream, _readerSettings))
  159. {
  160. var context = BsonDeserializationContext.CreateRoot(bsonReader);
  161. bsonReader.ReadStartDocument();
  162. BsonType bsonType;
  163. while ((bsonType = bsonReader.ReadBsonType()) != BsonType.EndOfDocument)
  164. {
  165. bsonReader.SkipName();
  166. BsonValue value;
  167. switch (bsonType)
  168. {
  169. case BsonType.Array: value = DeserializeLazyBsonArray(bsonReader); break;
  170. case BsonType.Document: value = DeserializeLazyBsonDocument(bsonReader); break;
  171. default: value = BsonValueSerializer.Instance.Deserialize(context); break;
  172. }
  173. values.Add(value);
  174. }
  175. bsonReader.ReadEndDocument();
  176. }
  177. return values;
  178. }
  179. }
  180. }