/* Copyright 2010-present MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Misc; namespace MongoDB.Driver { /// /// Vector search query vector. /// public sealed class QueryVector { /// /// Gets the underlying bson value representing the vector. /// Possible values are or encoding /// internal BsonValue Vector { get; } // do not make public because in the case of ReadOnlyMemory the BsonArray subclass is not fully functional private QueryVector(BsonArray array) { Ensure.IsNotNullOrEmpty(array, nameof(array)); Vector = array; } /// /// Initializes a new instance of the class. /// /// The bson binary data. public QueryVector(BsonBinaryData bsonBinaryData) { Ensure.IsNotNull(bsonBinaryData, nameof(bsonBinaryData)); Ensure.IsEqualTo(bsonBinaryData.SubType, BsonBinarySubType.Vector, nameof(bsonBinaryData.SubType)); Vector = bsonBinaryData; } /// /// Initializes a new instance of the class. /// /// The memory. public QueryVector(ReadOnlyMemory readOnlyMemory) : this(new QueryVectorBsonArray(readOnlyMemory)) { } /// /// Initializes a new instance of the class. /// /// The memory. public QueryVector(ReadOnlyMemory readOnlyMemory) : this(new QueryVectorBsonArray(readOnlyMemory)) { } /// /// Initializes a new instance of the class. /// /// The memory. public QueryVector(ReadOnlyMemory readOnlyMemory) : this(new QueryVectorBsonArray(readOnlyMemory)) { } /// /// Performs an implicit conversion from [] to . /// /// The array. /// /// The result of the conversion. /// public static implicit operator QueryVector(double[] array) => new(array); /// /// Performs an implicit conversion from a of to . /// /// The readOnlyMemory. /// /// The result of the conversion. /// public static implicit operator QueryVector(ReadOnlyMemory readOnlyMemory) => new(readOnlyMemory); /// /// Performs an implicit conversion from [] to . /// /// The array. /// /// The result of the conversion. /// public static implicit operator QueryVector(float[] array) => new(array); /// /// Performs an implicit conversion from a of to . /// /// The readOnlyMemory. /// /// The result of the conversion. /// public static implicit operator QueryVector(ReadOnlyMemory readOnlyMemory) => new(readOnlyMemory); /// /// Performs an implicit conversion from [] to . /// /// The array. /// /// The result of the conversion. /// public static implicit operator QueryVector(int[] array) => new(array); /// /// Performs an implicit conversion from a of to . /// /// The readOnlyMemory. /// /// The result of the conversion. /// public static implicit operator QueryVector(ReadOnlyMemory readOnlyMemory) => new(readOnlyMemory); /// /// Performs an implicit conversion from a of to . /// /// The binary vector int8. /// /// The result of the conversion. /// [CLSCompliant(false)] public static implicit operator QueryVector(BinaryVectorInt8 binaryVectorInt8) => binaryVectorInt8.ToQueryVector(); /// /// Performs an implicit conversion from a of to . /// /// The binary vector float32. /// /// The result of the conversion. /// public static implicit operator QueryVector(BinaryVectorFloat32 binaryVectorFloat32) => binaryVectorFloat32.ToQueryVector(); /// /// Performs an implicit conversion from a of to . /// /// The binary vector packed bit. /// /// The result of the conversion. /// public static implicit operator QueryVector(BinaryVectorPackedBit binaryVectorPackedBit) => binaryVectorPackedBit.ToQueryVector(); } // WARNING: this class is a very partial implementation of a BsonArray subclass // it is not fully functional and is only intended to be serialized [BsonSerializer(typeof(QueryVectorArraySerializer<>))] internal sealed class QueryVectorBsonArray : BsonArray where T : struct, IConvertible { private readonly ReadOnlyMemory _memory; public QueryVectorBsonArray(ReadOnlyMemory memory) { _memory = memory; } // note: Count is only used in tests public override int Count => _memory.Length; public ReadOnlySpan Span => _memory.Span; // note: Values is only used in tests public override IEnumerable Values { get { for (int i = 0; i < _memory.Span.Length; i++) { yield return _memory.Span[i].ToDouble(null); } } } } internal sealed class QueryVectorArraySerializer : BsonValueSerializerBase> where T : struct, IConvertible { // constructors public QueryVectorArraySerializer() : base(BsonType.Array) { } // protected methods protected override QueryVectorBsonArray DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) => throw new NotImplementedException(); protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, QueryVectorBsonArray value) { var bsonWriter = context.Writer; var span = value.Span; bsonWriter.WriteStartArray(); for (int i = 0; i < value.Count; i++) { bsonWriter.WriteDouble(span[i].ToDouble(null)); } bsonWriter.WriteEndArray(); } } }