U
    Ä“«jF  ã                   @   s8   d dl Z d dlmZ G dd„ deƒZG dd„ deƒZdS )é    N)ÚIBatchedTimerc                   @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	Ú_BatchedCallzÃ
    Wraps IDelayedCall-implementing objects, implementing only the API
    which txaio promised in the first place: .cancel

    Do not create these yourself; use _BatchedTimer.call_later()
    c                 C   s   || _ || _|| _d S ©N)Ú_timerÚ_indexÚ_call)ÚselfZtimerÚindexZthe_call© r
   ú1/tmp/pip-unpacked-wheel-8qem9ucn/txaio/_common.pyÚ__init__'   s    z_BatchedCall.__init__c                 C   s   | j  | j| ¡ d | _ d S r   )r   Ú_remove_callr   ©r   r
   r
   r   Úcancel-   s    z_BatchedCall.cancelc                 C   s   |   ¡ S r   )r   r   r
   r
   r   Ú__call__1   s    z_BatchedCall.__call__N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r
   r
   r
   r   r      s   r   c                   @   s2   e Zd ZdZddd„Zdd„ Zdd„ Zd	d
„ ZdS )Ú_BatchedTimera=  
    Internal helper.

    Instances of this are returned from
    :meth:`txaio.make_batched_timer` and that is the only way they
    should be instantiated. You may depend on methods from the
    interface class only (:class:`txaio.IBatchedTimer`)

    **NOTE** that the times are in milliseconds in this class!
    Nc                 C   s>   |dkrt dƒ‚t|ƒ| _|| _|| _|| _tƒ | _|| _d S )Nç        z!bucket_milliseconds must be > 0.0)	Ú
ValueErrorÚfloatÚ_bucket_millisecondsÚ_chunk_sizeÚ_get_secondsÚ_create_delayed_callÚdictÚ_bucketsZ_loop)r   Zbucket_millisecondsÚ
chunk_sizeZseconds_providerZdelayed_call_creatorZloopr
   r
   r   r   A   s    ÿ
z_BatchedTimer.__init__c           
         s¦   |   ¡ }t|| ƒd }|t|| j ƒ8 }t| |‡ ‡‡fdd„ƒ}z| j| d  |¡ W nF tk
r    |d | }|  td|ƒ| j	|¡}	|	|gf| j|< Y nX |S )z#
        IBatchedTimer API
        iè  c                      s
   ˆˆ ˆŽS r   r
   r
   ©ÚargsÚfuncÚkwargsr
   r   Ú<lambda>V   ó    z*_BatchedTimer.call_later.<locals>.<lambda>é   ç     @�@r   )
r   Úintr   r   r   ÚappendÚKeyErrorr   ÚmaxÚ_notify_bucket)
r   Údelayr"   r!   r#   ÚnowÚ	real_timeÚcallZdiffÚdelayed_callr
   r    r   Ú
call_laterN   s     þz_BatchedTimer.call_laterc                    s`   ˆj | \}}ˆj |= g ‰ ‡ ‡‡fdd„‰ˆjt tt|ƒƒˆj ¡ }ˆ|ˆjtd|ƒƒ dS )z�
        Internal helper. This 'does' the callbacks in a particular bucket.

        :param real_time: the bucket to do callbacks on
        c                    s¢   | d |… D ]<}z
|ƒ  W q t k
rF } zˆ  |¡ W 5 d }~X Y qX q| |d … } | rrˆ |d ˆ| ||¡ n,tˆ ƒržd}ˆ D ]}|d |¡7 }q‚t|ƒ‚d S )Nr'   z'Error(s) processing call_later bucket:
z{}
)Ú	Exceptionr)   r   ÚlenÚformatÚRuntimeError)Úcallsr   Zchunk_delay_msr0   ÚeÚmsg©ÚerrorsÚnotify_one_chunkr   r
   r   r<   p   s&    
   þz6_BatchedTimer._notify_bucket.<locals>.notify_one_chunkr   N)r   r   ÚmathÚceilr   r4   r   r+   )r   r/   r1   r7   Zdelay_msr
   r:   r   r,   f   s    z_BatchedTimer._notify_bucketc                 C   sL   z| j | \}}W n tk
r(   Y dS X | |¡ |sH| j |= | ¡  dS )zº
        Internal helper. Removes a (possibly still pending) call from a
        bucket. It is *not* an error of the bucket is gone (e.g. the
        call has already happened).
        N)r   r*   Úremover   )r   r/   r0   r1   r7   r
   r
   r   r   Š   s    
z_BatchedTimer._remove_call)N)r   r   r   r   r   r2   r,   r   r
   r
   r
   r   r   5   s    ÿ
$r   )r=   Ztxaio.interfacesr   Úobjectr   r   r
   r
   r
   r   Ú<module>   s   