/* 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;
}
}
}