classdef GatherableMixin
    %GATHERABLEMIXIN Mixin class for statistical classes that need to implement GATHER
    %

    %   Copyright 2020-2023 The MathWorks, Inc.
    
    methods
        function varargout = gather(varargin)
            %GATHER Gather an object.
            %   GOBJ = GATHER(OBJ) gathers all properties of the input
            %   object OBJ and returns the gathered object as GOBJ. All
            %   properties of the output GOBJ are stored in the local
            %   workspace.
            %
            %   [GOBJ1,GOBJ2,...,GOBJn] =  GATHER(OBJ1,OBJ2,...,OBJn)
            %   gathers multiple objects OBJ1,OBJ2,...,OBJn into the
            %   corresponding outputs GOBJ1,GOBJ2,...,GOBJn.
            %
            %   If all the properties of an input are stored in the local
            %   workspace, then the corresponding output is the same as the
            %   input.
            %
            %   Use this method to create an object whose properties are
            %   all stored in the local workspace from an object that has
            %   properties stored as gpuArrays.
            %
            %   See also gather, gpuArray/gather.
            if nargout > nargin
                error(message("MATLAB:nargoutchk:tooManyOutputs"));
            end
            
            if nargin==1
                % Short-cut for single input
                varargout = {gatherOne(varargin{1})};
                return
            end
            
            % Gather the GatherableMixins
            isGatherableMixin = cellfun(@(x) isa(x, mfilename('class')), varargin);
            varargout(isGatherableMixin) = cellfun(@gatherOne, varargin(isGatherableMixin), ...
                'UniformOutput', false);
            
            % Gather all other arguments
            if any(~isGatherableMixin)
                [varargout{~isGatherableMixin}] = gather(varargin{~isGatherableMixin});
            end
        end
    end
    
    methods (Abstract, Access = protected)
        obj = gatherOne(obj)
    end

    methods (Hidden, Access = protected)
        % Gathers all fields of a struct. Return empty arrays unchanged to
        % avoid calling code having to check whether a struct has been
        % assigned.
        function str = gatherStruct(~, str)
            if isempty(str)
                return
            end
            values = struct2cell(str);
            [values{:}] = gather(values{:});
            str = cell2struct(values,fieldnames(str),1);
        end
    end
end
