function C = copyFunctionHandleToWorkers(fHandle)
%copyFunctionHandleToWorkers Copy objective function handle to parallel
%workers, sending any required code.
%
%   C = copyFunctionHandleToWorkers(fHandle) copies the function handle
%   fHandle to all workers in the current parallel pool, and sends any code
%   required to execute the function on the workers. C is an object of
%   class parallel.pool.Constant.

%   Copyright 2017-2023 The MathWorks, Inc.

% Attach files to pool unless it is a thread pool, which doesn't need files
% to be attached. IMPORTANT: Files must be attached BEFORE sending the
% function handle.
if ~isa(gcp, 'parallel.ThreadPool')
    attachMissingFunctionHandleFilesToPool(fHandle, gcp);
end

% Use an anonymous function that will be evaluated on workers to set the
% function handle into the constant.
C = parallel.pool.Constant(@() fHandle);
end

function attachMissingFunctionHandleFilesToPool(fHandle, pool)
% The command
% parallel.internal.apishared.AttachedFiles.convertFunctionHandleForDependencyAnalysis(fHandle)
% is internal and may not be supported in the future.
NeededFunctionsAndFiles = parallel.internal.apishared.AttachedFiles.convertFunctionHandleForDependencyAnalysis(fHandle);
Paths = cellfun(@which, NeededFunctionsAndFiles, 'UniformOutput',false);

% Remove empty paths. This can occur when a needed function is locally
% defined inside a script file which is already being attached.
Paths(cellfun(@isempty, Paths)) = [];

Builtin = cellfun(@isBuiltin, Paths);
ToAttach = setdiff(Paths(~Builtin), pool.AttachedFiles);
if ~isempty(ToAttach)
    pool.addAttachedFiles(ToAttach);
end
end

function tf = isBuiltin(path)
tf = strncmp(path, 'built-in', 8);
end
