U
    d'                  	   @   s6  d Z ddlZddlZddlmZmZmZmZmZ e	dj
Ze	djZdZdZdZdZd	Zd
ZdZdZdZee dfZedfZee dfZedfZee dfZedfZeejeedg ejejej gddZ!ej"f e!# Z$eej%e&e'ee(ee( e(f f Z)ej"dddZ*e)ee(e(f dddZ+G dd dZ,dS )zHTools for working with the BSON decimal128 type.

.. versionadded:: 3.4
    N)AnySequenceTupleTypeUnionz<Ql            i   i   i"   l          @ l          ` l          p l               )precroundingEminEmaxcapitalsflagstrapsclampreturnc                  C   s   t  } g | d< tjf | S )zReturns an instance of :class:`decimal.Context` appropriate
    for working with IEEE-754 128-bit decimal floating point values.
    r   )_CTX_OPTIONScopydecimalContext)opts r   3/tmp/pip-unpacked-wheel-oblwsawz/bson/decimal128.pycreate_decimal128_context<   s    r   valuer   c              	   C   s\  t t}|| } W 5 Q R X |  r8|  r4tS tS |  \}}}| 	 r|rZt
d|  rr|  rntS tS |  r~tS tS tddd |D }| }d}d}ttd|D ]}	|d|	> @ r|d|	> O }qtd|D ] }	|d|	> @ r|d|	d > O }q|t }
|d? dkr:|d	@ }|tO }||
d
@ d> O }n||
d> O }|rT|tO }||fS )zConverts a decimal.Decimal to BID (high bits, low bits).

    :Parameters:
      - `value`: An instance of decimal.Decimal
    z'NaN with debug payload is not supported c                 S   s   g | ]}t |qS r   str.0digitr   r   r   
<listcomp>Z   s     z#_decimal_to_128.<locals>.<listcomp>r   @   r   1   l    i?  /   )r   localcontext_DEC128_CTXcreate_decimalis_infinite	is_signed_NINF_PINFas_tupleis_nan
ValueErroris_snan_NSNAN_PSNAN_NNAN_PNANintjoin
bit_lengthrangemin_EXPONENT_BIAS_EXPONENT_MASK_SIGN)r   ctxsigndigitsexponentZsignificandr8   highlowiZbiased_exponentr   r   r   _decimal_to_128E   s<    rE   c                   @   s   e Zd ZdZdZdZeddddZej	dd	d
Z
eed  ed dddZeedddZedddZedddZeeef ddddZeeef dddZeedddZeedddZdS )
Decimal128a  BSON Decimal128 type::

      >>> Decimal128(Decimal("0.0005"))
      Decimal128('0.0005')
      >>> Decimal128("0.0005")
      Decimal128('0.0005')
      >>> Decimal128((3474527112516337664, 5))
      Decimal128('0.0005')

    :Parameters:
      - `value`: An instance of :class:`decimal.Decimal`, string, or tuple of
        (high bits, low bits) from Binary Integer Decimal (BID) format.

    .. note:: :class:`~Decimal128` uses an instance of :class:`decimal.Context`
      configured for IEEE-754 Decimal128 when validating parameters.
      Signals like :class:`decimal.InvalidOperation`, :class:`decimal.Inexact`,
      and :class:`decimal.Overflow` are trapped and raised as exceptions::

        >>> Decimal128(".13.1")
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
          ...
        decimal.InvalidOperation: [<class 'decimal.ConversionSyntax'>]
        >>>
        >>> Decimal128("1E-6177")
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
          ...
        decimal.Inexact: [<class 'decimal.Inexact'>]
        >>>
        >>> Decimal128("1E6145")
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
          ...
        decimal.Overflow: [<class 'decimal.Overflow'>, <class 'decimal.Rounded'>]

      To ensure the result of a calculation can always be stored as BSON
      Decimal128 use the context returned by
      :func:`create_decimal128_context`::

        >>> import decimal
        >>> decimal128_ctx = create_decimal128_context()
        >>> with decimal.localcontext(decimal128_ctx) as ctx:
        ...     Decimal128(ctx.create_decimal(".13.3"))
        ...
        Decimal128('NaN')
        >>>
        >>> with decimal.localcontext(decimal128_ctx) as ctx:
        ...     Decimal128(ctx.create_decimal("1E-6177"))
        ...
        Decimal128('0E-6176')
        >>>
        >>> with decimal.localcontext(DECIMAL128_CTX) as ctx:
        ...     Decimal128(ctx.create_decimal("1E6145"))
        ...
        Decimal128('Infinity')

      To match the behavior of MongoDB's Decimal128 implementation
      str(Decimal(value)) may not match str(Decimal128(value)) for NaN values::

        >>> Decimal128(Decimal('NaN'))
        Decimal128('NaN')
        >>> Decimal128(Decimal('-NaN'))
        Decimal128('NaN')
        >>> Decimal128(Decimal('sNaN'))
        Decimal128('NaN')
        >>> Decimal128(Decimal('-sNaN'))
        Decimal128('NaN')

      However, :meth:`~Decimal128.to_decimal` will return the exact value::

        >>> Decimal128(Decimal('NaN')).to_decimal()
        Decimal('NaN')
        >>> Decimal128(Decimal('-NaN')).to_decimal()
        Decimal('-NaN')
        >>> Decimal128(Decimal('sNaN')).to_decimal()
        Decimal('sNaN')
        >>> Decimal128(Decimal('-sNaN')).to_decimal()
        Decimal('-sNaN')

      Two instances of :class:`Decimal128` compare equal if their Binary
      Integer Decimal encodings are equal::

        >>> Decimal128('NaN') == Decimal128('NaN')
        True
        >>> Decimal128('NaN').bid == Decimal128('NaN').bid
        True

      This differs from :class:`decimal.Decimal` comparisons for NaN::

        >>> Decimal('NaN') == Decimal('NaN')
        False
    )Z__highZ__low   Nr   c                 C   sf   t |ttjfr"t|\| _| _n@t |ttfrRt	|dkrDt
d|\| _| _ntd|dd S )N   zYInvalid size for creation of Decimal128 from list or tuple. Must have exactly 2 elements.zCannot convert z to Decimal128)
isinstancer   r   DecimalrE   _Decimal128__high_Decimal128__lowlisttuplelenr0   	TypeErrorselfr   r   r   r   __init__   s    zDecimal128.__init__r   c           
   
   C   s  | j }| j}|t@ rdnd}|t@ tkr8t|ddfS |t@ tkrTt|ddfS |t@ tkrpt|ddfS |t@ tkr|d@ d? t	 }t|d	|fS |d
@ d? t	 }t
d}d}tdddD ]$}||@ d| d> ? ||< |d> }qd}tdddD ]&}||@ d| d> ? ||< |d> } qd}||@ d? |d< tdd tt|dD }tt}	|	|||fW  5 Q R  S Q R X dS )z^Returns an instance of :class:`decimal.Decimal` for this
        :class:`Decimal128`.
        r   r   r   NnFl          r&   )r   l          r%                     l          0   c                 s   s   | ]}t |V  qd S N)r6   r    r   r   r   	<genexpr>  s     z(Decimal128.to_decimal.<locals>.<genexpr>bigN)rK   rL   r=   _SNANr   rJ   _NAN_INFr<   r;   	bytearrayr9   rN   r   r6   
from_bytesr'   r(   r)   )
rR   rB   rC   r?   rA   ZarrmaskrD   r@   r>   r   r   r   
to_decimal   s6    
zDecimal128.to_decimal)clsr   r   c                 C   sR   t |tstdt|dkr&td| t|dd d t|dd d fS )zCreate an instance of :class:`Decimal128` from Binary Integer
        Decimal string.

        :Parameters:
          - `value`: 16 byte string (128-bit IEEE 754-2008 decimal floating
            point in Binary Integer Decimal (BID) format).
        z"value must be an instance of bytes   zvalue must be exactly 16 bytesr]   Nr   )rI   bytesrP   rO   r0   
_UNPACK_64)ri   r   r   r   r   from_bid  s
    	
zDecimal128.from_bidc                 C   s   t | jt | j S )z;The Binary Integer Decimal (BID) encoding of this instance.)_PACK_64rL   rK   rR   r   r   r   bid  s    zDecimal128.bidc                 C   s   |   }| rdS t|S )NNaN)rh   r/   r   )rR   decr   r   r   __str__$  s    zDecimal128.__str__c                 C   s   dt |  dS )NzDecimal128('z')r   ro   r   r   r   __repr__+  s    zDecimal128.__repr__c                 C   s   |\| _ | _d S r_   rK   rL   rQ   r   r   r   __setstate__.  s    zDecimal128.__setstate__c                 C   s   | j | jfS r_   ru   ro   r   r   r   __getstate__1  s    zDecimal128.__getstate__)otherr   c                 C   s   t |tr| j|jkS tS r_   )rI   rF   rp   NotImplementedrR   rx   r   r   r   __eq__4  s    
zDecimal128.__eq__c                 C   s
   | |k S r_   r   rz   r   r   r   __ne__9  s    zDecimal128.__ne__)__name__
__module____qualname____doc__	__slots__Z_type_marker_VALUE_OPTIONSrS   r   rJ   rh   classmethodr   rk   rm   propertyrp   r   rs   rt   r   r6   rv   rw   r   boolr{   r|   r   r   r   r   rF   v   s   ^)rF   )-r   r   structtypingr   r   r   r   r   Structpackrn   unpackrl   r<   r;   Z_EXPONENT_MAXZ_EXPONENT_MINZ_MAX_DIGITSrd   rc   rb   r=   r,   r-   r4   r5   r2   r3   ROUND_HALF_EVENInvalidOperationOverflowInexactr   r   r   r(   rJ   floatr   r6   r   r   rE   rF   r   r   r   r   <module>   sD    	1