%PollableDataQueue class that enables sending and polling for data
%
%   parallel.pool.PollableDataQueue enables transferring data or messages
%   from workers back to the client in a parallel pool, whilst a
%   computation is being carried out. This supports returning intermediate
%   values from the computation and indicating progress of the computation.
%   When data is received, it can be removed from the queue by calling the
%   poll method.
%
%   Use a parallel.pool.PollableDataQueue if you want to programmatically
%   drain the queue (using the poll method) when data is received from the
%   send method.
%
%   parallel.pool.PollableDataQueue methods:
%      send        - Send data from worker to client
%      poll        - Retrieve data sent from the worker
%
%   parallel.pool.PollableDataQueue properties:
%      QueueLength - Number of items currently held in the queue
%
%   See also: parallel.pool.DataQueue
classdef PollableDataQueue < parallel.internal.dataqueue.AbstractDataQueue

    % Copyright 2016-2021 The MathWorks, Inc.

    methods
        function obj = PollableDataQueue(varargin)
            narginchk(0, 1);
            obj@parallel.internal.dataqueue.AbstractDataQueue(varargin{:})
        end

        function [data, OK] = poll(obj, varargin)
            %POLL Poll for messages or data from different workers using a data queue
            %
            % Use the poll and send methods together to poll for and send messages or
            % data from different workers using a data queue.
            %
            % q = parallel.pool.PollableDataQueue constructs a data queue and returns
            % an object that can be used to send and poll for data. send(q, V)  sends a
            % message or data with the value V. poll(q)  polls for the result sometime
            % later and returns V as the answer.
            %
            % You can only use poll in the same process as the data queue was created
            % in.
            %
            % [V, OK] = poll(q, optionalTimeout) returns data with value V, and a
            % boolean true for OK  to indicate that data has been returned. If there is
            % no data in the queue, then an empty array is returned and a boolean false
            % for OK. Poll takes an optional timeout as the second parameter (in
            % seconds). In that case, the method may block for that time before
            % returning; if any data arrives in the queue during that period, that data
            % is returned.
            %
            % Example: send and poll for a message using a data queue
            %
            % q = parallel.pool.PollableDataQueue;
            % parfor i = 1
            %     send(q, i);
            % end
            % poll(q)
            % ans =
            %        1
            %
            % See also parallel.pool.DataQueue/send, parallel.pool.PollableDataQueue
            
            % When a DataQueue has been serialized across to a worker the
            % Queue property will be empty. So we need to guard against
            % this here.
            if ~obj.OnInstantiatingProcess
                error(message('MATLAB:parallel:dataqueue:NoQueue'));
            end
            % Have we got the right number of input arguments?
            narginchk(1, 2);
            if nargin > 1
                validateattributes(varargin{1}, {'numeric'}, {'nonnegative', 'scalar'}); 
            end
            
            % Now defer to the internal implementation
            [data, OK] = obj.pollImpl(varargin{:});
        end                                       
    end
    
    methods (Access = protected)
        function S = saveobj(obj)
            % NOTE: any object that wants to be saved in a special way
            % needs to implement it's own version of saveobj - we simply
            % defer to our base class implementation.
            S = saveobj@parallel.internal.dataqueue.AbstractDataQueue(obj);
        end
        
        function setShouldSignalMatlabOnDataArrival(obj)
            obj.Queue.stopNotifyingMatlabOnDataReceived();
        end
        
        function maybeDrainAndDispatchAllDataOnQueue(~)
            assert(false, 'PollableDataQueue should never have this method called');
        end            
    end
    
end