3
]ð]¹(  ã               @   sV  d Z ddlZddlZddlZddlmZmZ er8e	j
ZnddlZe	ejfdd„ZejdƒjZej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œZ&yej'dd� de&d< W n e(k
�r    de&d< Y nX ej'f e&j)ƒ ŽZ*dd„ Z+dd„ Z,G dd„ de-ƒZ.dS )zƒTools for working with the BSON decimal128 type.

.. versionadded:: 3.4

.. note:: The Decimal128 BSON type requires MongoDB 3.4+.
é    N)ÚPY3Ústring_typec             C   s   ||| ƒdƒS )z3An implementation of int.from_bytes for python 2.x.é   © )ÚvalueÚdummyÚ_intZ_hexlifyr   r   ú2/tmp/pip-build-20mum3z4/pymongo/bson/decimal128.pyÚ_from_bytes"   s    r
   z<Qé   é=   i   i   iÿ  é"   l          @ l          ` l          p l            é   )ÚprecÚroundingÚEminÚEmaxÚcapitalsÚflagsÚtraps)Úclampr   Z_clampc              C   s   t jƒ } g | d< tjf | ŽS )z…Returns an instance of :class:`decimal.Context` appropriate
    for working with IEEE-754 128-bit decimal floating point values.
    r   )Ú_CTX_OPTIONSÚcopyÚdecimalÚContext)Úoptsr   r   r	   Úcreate_decimal128_contextS   s    r   c             C   sd  t jtƒ�}|j| ƒ} W dQ R X | jƒ r8| jƒ r4tS tS | jƒ \}}}| j	ƒ r‚|rZt
dƒ‚| jƒ rr| jƒ rntS tS | jƒ r~tS tS tdjdd„ |D ƒƒƒ}|jƒ }d}d}x.ttd|ƒƒD ]}	|d|	> @ rº|d|	> O }qºW x.td|ƒD ] }	|d|	> @ ræ|d|	d > O }qæW |t }
|d	? dk�rB|d
@ }|tO }||
d@ d> O }n||
d	> O }|�r\|tO }||fS )zConverts a decimal.Decimal to BID (high bits, low bits).

    :Parameters:
      - `value`: An instance of decimal.Decimal
    Nz'NaN with debug payload is not supportedÚ c             S   s   g | ]}t |ƒ‘qS r   )Ústr)Ú.0Údigitr   r   r	   ú
<listcomp>q   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significandr6   ÚhighÚlowÚiZbiased_exponentr   r   r	   Ú_decimal_to_128\   s<    rC   c               @   sp   e Zd ZdZdZdZdd„ Zdd„ Zed	d
„ ƒZ	e
dd„ ƒZdd„ Zdd„ Zdd„ Zdd„ Zdd„ Z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
    Ú__highÚ__lowé   c             C   sd   t |ttjfƒr"t|ƒ\| _| _n>t |ttfƒrRt	|ƒdkrDt
dƒ‚|\| _| _ntd|f ƒ‚d S )Né   zYInvalid size for creation of Decimal128 from list or tuple. Must have exactly 2 elements.zCannot convert %r to Decimal128)Ú
isinstanceÚ_string_typer   ÚDecimalrC   Ú_Decimal128__highÚ_Decimal128__lowÚlistÚtupleÚlenr.   Ú	TypeError)Úselfr   r   r   r	   Ú__init__ï   s    zDecimal128.__init__c       
      C   s€  | j }| j}|t@ rdnd}|t@ tkr8tj|f dfƒS |t@ tkrTtj|f dfƒS |t@ tkrptj|f dfƒS |t@ tkrœ|d@ d? t	 }tj|d|fƒS |d@ d	? t	 }t
d
ƒ}d}x4tdddƒD ]$}||@ d| d> ? ||< |d> }qÆW d}x6tdddƒD ]&}||@ d| d> ? ||< |d> }�q W d}||@ d? |d< tdd„ tt|dƒƒD ƒƒ}tjtƒ�}	|	j|||fƒS Q R X dS )z^Returns an instance of :class:`decimal.Decimal` for this
        :class:`Decimal128`.
        r   r   ÚNÚnÚFl         ÿ r$   l         ü r#   é   éÿ   é   é   r   é   l          é0   c             s   s   | ]}t |ƒV  qd S )N)r4   )r   r    r   r   r	   ú	<genexpr>   s    z(Decimal128.to_decimal.<locals>.<genexpr>ÚbigN)r   éÿÿÿÿr_   )rL   rM   r;   Ú_SNANr   rK   Ú_NANÚ_INFr:   r9   Ú	bytearrayr7   rO   r   r
   r%   r&   r'   )
rR   r@   rA   r=   r?   ZarrÚmaskrB   r>   r<   r   r   r	   Ú
to_decimalû   s8    zDecimal128.to_decimalc             C   sR   t |tƒstdƒ‚t|ƒdkr&tdƒ‚| t|dd… ƒd t|dd… ƒd fƒS )zûCreate 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 bytesr   zvalue must be exactly 16 bytesr[   Nr   )rI   ÚbytesrQ   rP   r.   Ú
_UNPACK_64)Úclsr   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_64rM   rL   )rR   r   r   r	   Úbid4  s    zDecimal128.bidc             C   s   | j ƒ }|jƒ rdS t|ƒS )NÚNaN)re   r-   r   )rR   Údecr   r   r	   Ú__str__9  s    zDecimal128.__str__c             C   s   dt | ƒf S )NzDecimal128('%s'))r   )rR   r   r   r	   Ú__repr__@  s    zDecimal128.__repr__c             C   s   |\| _ | _d S )N)rL   rM   )rR   r   r   r   r	   Ú__setstate__C  s    zDecimal128.__setstate__c             C   s   | j | jfS )N)rL   rM   )rR   r   r   r	   Ú__getstate__F  s    zDecimal128.__getstate__c             C   s   t |tƒr| j|jkS tS )N)rI   rD   rk   ÚNotImplemented)rR   Úotherr   r   r	   Ú__eq__I  s    
zDecimal128.__eq__c             C   s
   | |k S )Nr   )rR   rs   r   r   r	   Ú__ne__N  s    zDecimal128.__ne__N)rE   rF   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú	__slots__Z_type_markerrS   re   Úclassmethodri   Úpropertyrk   rn   ro   rp   rq   rt   ru   r   r   r   r	   rD   �   s   ]*rD   l            ièÿÿ)/ry   r   ÚstructÚsysZbson.py3compatr   Z_PY3r   rJ   r4   Ú
from_bytesr
   ÚbinasciiÚhexlifyÚStructÚpackrj   Úunpackrg   r:   r9   Z_EXPONENT_MAXZ_EXPONENT_MINZ_MAX_DIGITSrb   ra   r`   r;   r*   r+   r2   r3   r0   r1   ÚROUND_HALF_EVENÚInvalidOperationÚOverflowÚInexactr   r   rQ   r   r&   r   rC   ÚobjectrD   r   r   r   r	   Ú<module>   sV   	1