/* 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 MongoDB.Bson.Serialization.Attributes; namespace MongoDB.Bson.Serialization.Options { /// /// Represents the external representation of a field or property. /// public class RepresentationConverter { // private fields private bool _allowOverflow; private bool _allowTruncation; // constructors /// /// Initializes a new instance of the RepresentationConverter class. /// /// Whether to allow overflow. /// Whether to allow truncation. public RepresentationConverter(bool allowOverflow, bool allowTruncation) { _allowOverflow = allowOverflow; _allowTruncation = allowTruncation; } // public properties /// /// Gets whether to allow overflow. /// public bool AllowOverflow { get { return _allowOverflow; } } /// /// Gets whether to allow truncation. /// public bool AllowTruncation { get { return _allowTruncation; } } // public methods /// /// Converts a Decimal128 to a Decimal. /// /// A Decimal128. /// A Decimal. public decimal ToDecimal(Decimal128 value) { if (value == Decimal128.MaxValue) { return decimal.MaxValue; } else if (value == Decimal128.MinValue) { return decimal.MinValue; } else if (Decimal128.IsInfinity(value) || Decimal128.IsNaN(value)) { throw new OverflowException(); } decimal decimalValue; if (_allowOverflow) { try { decimalValue = (decimal)value; } catch (OverflowException) { decimalValue = Decimal128.IsNegative(value) ? decimal.MinValue : decimal.MaxValue; } } else { decimalValue = (decimal)value; } if (!_allowTruncation && value != (Decimal128)decimalValue) { throw new TruncationException(); } return decimalValue; } /// /// Converts a Double to a Decimal. /// /// A Double. /// A Decimal. public decimal ToDecimal(double value) { if (value == double.MinValue) { return decimal.MinValue; } else if (value == double.MaxValue) { return decimal.MaxValue; } var decimalValue = (decimal)value; if (value < (double)decimal.MinValue || value > (double)decimal.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } else if (value != (double)decimalValue) { if (!_allowTruncation) { throw new TruncationException(); } } return decimalValue; } /// /// Converts an Int32 to a Decimal. /// /// An Int32. /// A Decimal. public decimal ToDecimal(int value) { return (decimal)value; } /// /// Converts an Int64 to a Decimal. /// /// An Int64. /// A Decimal. public decimal ToDecimal(long value) { return (decimal)value; } /// /// Converts a decimal to a Decimal128. /// /// A decimal. /// A Decimal128. public Decimal128 ToDecimal128(decimal value) { if (value == decimal.MaxValue) { return Decimal128.MaxValue; } else if (value == decimal.MinValue) { return Decimal128.MinValue; } // conversion from decimal to Decimal128 is lossless so need to check for overflow or truncation return (Decimal128)value; } /// /// Converts a Double to a Decimal128. /// /// A Double. /// A Decimal128. public Decimal128 ToDecimal128(double value) { if (value == double.MaxValue) { return Decimal128.MaxValue; } else if (value == double.MinValue) { return Decimal128.MinValue; } else if (double.IsPositiveInfinity(value)) { return Decimal128.PositiveInfinity; } else if (double.IsNegativeInfinity(value)) { return Decimal128.NegativeInfinity; } else if (double.IsNaN(value)) { return Decimal128.QNaN; } var decimal128Value = (Decimal128)value; if (!_allowTruncation && value != (double)decimal128Value) { throw new TruncationException(); } return decimal128Value; } /// /// Converts an Int32 to a Decimal128. /// /// An Int32. /// A Decimal128. public Decimal128 ToDecimal128(int value) { return (Decimal128)value; } /// /// Converts an Int64 to a Decimal128. /// /// An Int64. /// A Decimal128. public Decimal128 ToDecimal128(long value) { return (Decimal128)value; } /// /// Converts a UInt64 to a Decimal128. /// /// A UInt64. /// A Decimal128. [CLSCompliant(false)] public Decimal128 ToDecimal128(ulong value) { return (Decimal128)value; } /// /// Converts a Decimal to a Double. /// /// A Decimal. /// A Double. public double ToDouble(decimal value) { if (value == decimal.MinValue) { return double.MinValue; } else if (value == decimal.MaxValue) { return double.MaxValue; } var doubleValue = (double)value; if (value != (decimal)doubleValue) { if (!_allowTruncation) { throw new TruncationException(); } } return doubleValue; } /// /// Converts a Decimal128 to a Double. /// /// A Decimal. /// A Double. public double ToDouble(Decimal128 value) { if (value == Decimal128.MaxValue) { return double.MaxValue; } else if (value == Decimal128.MinValue) { return double.MinValue; } else if (Decimal128.IsPositiveInfinity(value)) { return double.PositiveInfinity; } else if (Decimal128.IsNegativeInfinity(value)) { return double.NegativeInfinity; } else if (Decimal128.IsNaN(value)) { return double.NaN; } double doubleValue; if (_allowOverflow) { try { doubleValue = (double)value; } catch (OverflowException) { doubleValue = Decimal128.IsNegative(value) ? double.MinValue : double.MaxValue; } } else { doubleValue = (double)value; } if (!_allowTruncation && value != (Decimal128)doubleValue) { throw new TruncationException(); } return doubleValue; } /// /// Converts a Double to a Double. /// /// A Double. /// A Double. public double ToDouble(double value) { return value; } /// /// Converts a Single to a Double. /// /// A Single. /// A Double. public double ToDouble(float value) { if (value == float.MinValue) { return double.MinValue; } else if (value == float.MaxValue) { return double.MaxValue; } else if (float.IsNegativeInfinity(value)) { return double.NegativeInfinity; } else if (float.IsPositiveInfinity(value)) { return double.PositiveInfinity; } else if (float.IsNaN(value)) { return double.NaN; } return value; } /// /// Converts an Int32 to a Double. /// /// An Int32. /// A Double. public double ToDouble(int value) { return value; } /// /// Converts an Int64 to a Double. /// /// An Int64. /// A Double. public double ToDouble(long value) { var doubleValue = (double)value; if (value != (long)doubleValue) { if (!_allowTruncation) { throw new TruncationException(); } } return doubleValue; } /// /// Converts an Int16 to a Double. /// /// An Int16. /// A Double. public double ToDouble(short value) { return value; } /// /// Converts a UInt32 to a Double. /// /// A UInt32. /// A Double. [CLSCompliant(false)] public double ToDouble(uint value) { return value; } /// /// Converts a UInt64 to a Double. /// /// A UInt64. /// A Double. [CLSCompliant(false)] public double ToDouble(ulong value) { var doubleValue = (double)value; if (value != (ulong)doubleValue) { if (!_allowTruncation) { throw new TruncationException(); } } return doubleValue; } /// /// Converts a UInt16 to a Double. /// /// A UInt16. /// A Double. [CLSCompliant(false)] public double ToDouble(ushort value) { return value; } /// /// Converts a Decimal128 to an Int16. /// /// A Decimal128. /// An Int16. public short ToInt16(Decimal128 value) { short shortValue; if (_allowOverflow) { try { shortValue = (short)value; } catch (OverflowException) { shortValue = Decimal128.IsNegative(value) ? short.MinValue : short.MaxValue; } } else { shortValue = (short)value; } if (!_allowTruncation && value != (Decimal128)shortValue) { throw new TruncationException(); } return shortValue; } /// /// Converts a Double to an Int16. /// /// A Double. /// An Int16. public short ToInt16(double value) { var int16Value = (short)value; if (value < short.MinValue || value > short.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } else if (value != (double)int16Value) { if (!_allowTruncation) { throw new TruncationException(); } } return int16Value; } /// /// Converts an Int32 to an Int16. /// /// An Int32. /// An Int16. public short ToInt16(int value) { if (value < short.MinValue || value > short.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } return (short)value; } /// /// Converts an Int64 to an Int16. /// /// An Int64. /// An Int16. public short ToInt16(long value) { if (value < short.MinValue || value > short.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } return (short)value; } /// /// Converts a Decimal to an Int32. /// /// A Decimal. /// An Int32. public int ToInt32(decimal value) { if (value == decimal.MinValue) { return int.MinValue; } else if (value == decimal.MaxValue) { return int.MaxValue; } var int32Value = (int)value; if (value < int.MinValue || value > int.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } else if (value != (decimal)int32Value) { if (!_allowTruncation) { throw new TruncationException(); } } return int32Value; } /// /// Converts a Decimal128 to an Int32. /// /// A Decimal128. /// An Int32. public int ToInt32(Decimal128 value) { int intValue; if (_allowOverflow) { try { intValue = (int)value; } catch (OverflowException) { intValue = Decimal128.IsNegative(value) ? int.MinValue : int.MaxValue; } } else { intValue = (int)value; } if (!_allowTruncation && value != (Decimal128)intValue) { throw new TruncationException(); } return intValue; } /// /// Converts a Double to an Int32. /// /// A Double. /// An Int32. public int ToInt32(double value) { var int32Value = (int)value; if (value < int.MinValue || value > int.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } else if (value != (double)int32Value) { if (!_allowTruncation) { throw new TruncationException(); } } return int32Value; } /// /// Converts a Single to an Int32. /// /// A Single. /// An Int32. public int ToInt32(float value) { var int32Value = (int)value; if (value < int.MinValue || value > int.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } else if (value != (float)int32Value) { if (!_allowTruncation) { throw new TruncationException(); } } return int32Value; } /// /// Converts an Int32 to an Int32. /// /// An Int32. /// An Int32. public int ToInt32(int value) { return value; } /// /// Converts an Int64 to an Int32. /// /// An Int64. /// An Int32. public int ToInt32(long value) { if (value < int.MinValue || value > int.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } return (int)value; } /// /// Converts an Int16 to an Int32. /// /// An Int16. /// An Int32. public int ToInt32(short value) { return value; } /// /// Converts a UInt32 to an Int32. /// /// A UInt32. /// An Int32. [CLSCompliant(false)] public int ToInt32(uint value) { if (value > (uint)int.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } return (int)value; } /// /// Converts a UInt64 to an Int32. /// /// A UInt64. /// An Int32. [CLSCompliant(false)] public int ToInt32(ulong value) { if (value > (ulong)int.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } return (int)value; } /// /// Converts a UInt16 to an Int32. /// /// A UInt16. /// An Int32. [CLSCompliant(false)] public int ToInt32(ushort value) { return value; } /// /// Converts a Decimal to an Int64. /// /// A Decimal. /// An Int64. public long ToInt64(decimal value) { if (value == decimal.MinValue) { return long.MinValue; } else if (value == decimal.MaxValue) { return long.MaxValue; } var int64Value = (long)value; if (value < long.MinValue || value > long.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } else if (value != (decimal)int64Value) { if (!_allowTruncation) { throw new TruncationException(); } } return int64Value; } /// /// Converts a Decimal128 to an Int64. /// /// A Decimal128. /// An Int64. public long ToInt64(Decimal128 value) { long longValue; if (_allowOverflow) { try { longValue = (long)value; } catch (OverflowException) { longValue = Decimal128.IsNegative(value) ? long.MinValue : long.MaxValue; } } else { longValue = (long)value; } if (!_allowTruncation && value != (Decimal128)longValue) { throw new TruncationException(); } return longValue; } /// /// Converts a Double to an Int64. /// /// A Double. /// An Int64. public long ToInt64(double value) { var int64Value = (long)value; if (value < long.MinValue || value > long.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } else if (value != (double)int64Value) { if (!_allowTruncation) { throw new TruncationException(); } } return int64Value; } /// /// Converts a Single to an Int64. /// /// A Single. /// An Int64. public long ToInt64(float value) { var int64Value = (long)value; if (value < long.MinValue || value > long.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } else if (value != (float)int64Value) { if (!_allowTruncation) { throw new TruncationException(); } } return int64Value; } /// /// Converts an Int32 to an Int64. /// /// An Int32. /// An Int64. public long ToInt64(int value) { return value; } /// /// Converts an Int64 to an Int64. /// /// An Int64. /// An Int64. public long ToInt64(long value) { return value; } /// /// Converts an Int16 to an Int64. /// /// An Int16. /// An Int64. public long ToInt64(short value) { return value; } /// /// Converts a UInt32 to an Int64. /// /// A UInt32. /// An Int64. [CLSCompliant(false)] public long ToInt64(uint value) { return (long)value; } /// /// Converts a UInt64 to an Int64. /// /// A UInt64. /// An Int64. [CLSCompliant(false)] public long ToInt64(ulong value) { if (value > (ulong)long.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } return (long)value; } /// /// Converts a UInt16 to an Int64. /// /// A UInt16. /// An Int64. [CLSCompliant(false)] public long ToInt64(ushort value) { return value; } /// /// Converts a Decimal128 to a Single. /// /// A Decimal128. /// A Single. public float ToSingle(Decimal128 value) { if (value == Decimal128.MaxValue) { return float.MaxValue; } else if (value == Decimal128.MinValue) { return float.MinValue; } else if (Decimal128.IsPositiveInfinity(value)) { return float.PositiveInfinity; } else if (Decimal128.IsNegativeInfinity(value)) { return float.NegativeInfinity; } else if (Decimal128.IsNaN(value)) { return float.NaN; } float floatValue; if (_allowOverflow) { try { floatValue = (float)value; } catch (OverflowException) { floatValue = Decimal128.IsNegative(value) ? float.MinValue : float.MaxValue; } } else { floatValue = (float)value; } if (!_allowTruncation && value != (Decimal128)floatValue) { throw new TruncationException(); } return floatValue; } /// /// Converts a Double to a Single. /// /// A Double. /// A Single. public float ToSingle(double value) { if (value == double.MinValue) { return float.MinValue; } else if (value == double.MaxValue) { return float.MaxValue; } else if (double.IsNegativeInfinity(value)) { return float.NegativeInfinity; } else if (double.IsPositiveInfinity(value)) { return float.PositiveInfinity; } else if (double.IsNaN(value)) { return float.NaN; } var floatValue = (float)value; if (value < float.MinValue || value > float.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } else if (value != (double)floatValue) { if (!_allowTruncation) { throw new TruncationException(); } } return floatValue; } /// /// Converts an Int32 to a Single. /// /// An Int32. /// A Single. public float ToSingle(int value) { var floatValue = (float)value; if (value != (int)floatValue) { if (!_allowTruncation) { throw new TruncationException(); } } return floatValue; } /// /// Converts an Int64 to a Single. /// /// An Int64. /// A Single. public float ToSingle(long value) { var floatValue = (float)value; if (value != (long)floatValue) { if (!_allowTruncation) { throw new TruncationException(); } } return floatValue; } /// /// Converts a Decimal128 to a UInt16. /// /// A Decimal128. /// A UInt16. [CLSCompliant(false)] public ushort ToUInt16(Decimal128 value) { ushort ushortValue; if (_allowOverflow) { try { ushortValue = (ushort)value; } catch (OverflowException) { ushortValue = Decimal128.IsNegative(value) ? ushort.MinValue : ushort.MaxValue; } } else { ushortValue = (ushort)value; } if (!_allowTruncation && value != (Decimal128)ushortValue) { throw new TruncationException(); } return ushortValue; } /// /// Converts a Double to a UInt16. /// /// A Double. /// A UInt16. [CLSCompliant(false)] public ushort ToUInt16(double value) { var uint16Value = (ushort)value; if (value < ushort.MinValue || value > ushort.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } else if (value != (double)uint16Value) { if (!_allowTruncation) { throw new TruncationException(); } } return uint16Value; } /// /// Converts an Int32 to a UInt16. /// /// An Int32. /// A UInt16. [CLSCompliant(false)] public ushort ToUInt16(int value) { if (value < ushort.MinValue || value > ushort.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } return (ushort)value; } /// /// Converts an Int64 to a UInt16. /// /// An Int64. /// A UInt16. [CLSCompliant(false)] public ushort ToUInt16(long value) { if (value < ushort.MinValue || value > ushort.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } return (ushort)value; } /// /// Converts a Decimal128 to a UInt32. /// /// A Decimal128. /// A UInt32. [CLSCompliant(false)] public uint ToUInt32(Decimal128 value) { uint uintValue; if (_allowOverflow) { try { uintValue = (uint)value; } catch (OverflowException) { uintValue = Decimal128.IsNegative(value) ? uint.MinValue : uint.MaxValue; } } else { uintValue = (uint)value; } if (!_allowTruncation && value != (Decimal128)uintValue) { throw new TruncationException(); } return uintValue; } /// /// Converts a Double to a UInt32. /// /// A Double. /// A UInt32. [CLSCompliant(false)] public uint ToUInt32(double value) { var uint32Value = (uint)value; if (value < uint.MinValue || value > uint.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } else if (value != (double)uint32Value) { if (!_allowTruncation) { throw new TruncationException(); } } return uint32Value; } /// /// Converts an Int32 to a UInt32. /// /// An Int32. /// A UInt32. [CLSCompliant(false)] public uint ToUInt32(int value) { if (value < uint.MinValue) { if (!_allowOverflow) { throw new OverflowException(); } } return (uint)value; } /// /// Converts an Int64 to a UInt32. /// /// An Int64. /// A UInt32. [CLSCompliant(false)] public uint ToUInt32(long value) { if (value < uint.MinValue || value > uint.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } return (uint)value; } /// /// Converts a Decimal128 to a UInt64. /// /// A Decimal128. /// A UInt64. [CLSCompliant(false)] public ulong ToUInt64(Decimal128 value) { ulong ulongValue; if (_allowOverflow) { try { ulongValue = (ulong)value; } catch (OverflowException) { ulongValue = Decimal128.IsNegative(value) ? ulong.MinValue : ulong.MaxValue; } } else { ulongValue = (ulong)value; } if (!_allowTruncation && value != (Decimal128)ulongValue) { throw new TruncationException(); } return ulongValue; } /// /// Converts a Double to a UInt64. /// /// A Double. /// A UInt64. [CLSCompliant(false)] public ulong ToUInt64(double value) { var uint64Value = (ulong)value; if (value < ulong.MinValue || value > ulong.MaxValue) { if (!_allowOverflow) { throw new OverflowException(); } } else if (value != (double)uint64Value) { if (!_allowTruncation) { throw new TruncationException(); } } return uint64Value; } /// /// Converts an Int32 to a UInt64. /// /// An Int32. /// A UInt64. [CLSCompliant(false)] public ulong ToUInt64(int value) { if (value < (int)ulong.MinValue) { if (!_allowOverflow) { throw new OverflowException(); } } return (ulong)value; } /// /// Converts an Int64 to a UInt64. /// /// An Int64. /// A UInt64. [CLSCompliant(false)] public ulong ToUInt64(long value) { if (value < (int)ulong.MinValue) { if (!_allowOverflow) { throw new OverflowException(); } } return (ulong)value; } } }