%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Copyright © 2022 Maximilian Keßler
% 
% This work may be distributed and/or modified
% 
% 1. under the LaTeX Project Public License and/or
% 2. under the GNU General Public License
% 
% Distribution under conditions of the LaTeX Project Public License,
% requires either version 1.3 of this license or (at your option)
% any later version.
% The latest version of this license is in
%    http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
% 
% This work has the LPPL maintenance status \`maintained'.
% 
% The Current Maintainer of this work is Maximilian Keßler.
% 
% 
% Distribution under the GNU General Public License requires either
% version 3 or (at your opinion) any later version.
% 
% This package has been generated by PyTeX, available at
%    https://github.com/kesslermaximilian/PyTeX
% and built from source file 'cache.pysty3'.
% It is STRONGLY DISCOURAGED to edit this source file directly, since local
% changes will not be versioned by Git and overwritten by the next build. Always
% edit the source file and build the package again.
% 
% Build details:
%   PyTeX version: v1.2.0-31-gc9bb0e8 (commit c9bb0e8)
%   Source code version: v2.8.2 (commit b15dedb)
% 
% This LaTeX package is free software and is dual-licensed
% under the LPPLv1.3c and the GPLv3 licenses.
% You may use it freely for your purposes.
% The latest version of the package sources can be obtained
% via GitLab under
%    https://gitlab.com/latexci/packages/LatexPackages
% The latest version of the built packages can be obtained via GitLab under
%    https://gitlab.com/latexci/packages/LatexPackagesBuild
% For further information see the urls above.
% Reportings of bugs, suggestions and improvements are welcome, see the README
% at the Git repository for further information.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\ProvidesExplPackage{mkessler-cache}{2022/02/03}{2.8.2}{Cache definitions of previous LaTeX runs to avoid computations}





%%%% This is just a proof of concept package,
%%%% there is possibly more room for clean-up
%%%% and / or speed-up etc.

%%% Also, the provided 
%%% \DeclareCachedDocumentCommand
%%% is of course not really
%%% useful and just for demonstration
%%% purposes

\bool_new:N \g__cache_cache_bool
\int_new:N \g__cache_cache_version_document_int
\int_new:N \g__cache_cache_version_aux_int
\int_gset:Nn \g__cache_cache_version_aux_int { -1 }

\clist_new:N \g__cache_dump_auxfile_clist %% usual dump
\clist_new:N \g__cache_dump_cache_clist   %% will be dumped such that it is restored as \g__cache_lazy_auxfile_tl on next run.
\tl_new:N \g__cache_lazy_document_tl
\tl_new:N \g__cache_lazy_auxfile_tl

\keys_define:nn { cache }
  {
    cache              .bool_set:N    = \g__cache_cache_bool,
    cache              .default:n     = { true },
    __cache version__  .int_set:N     = \g__cache_cache_version_document_int,
    cache version      .meta:nn       = { cache } { cache = true, __cache version__ = #1 },
    cache version      .default:n     = { 0 },
  }
\RequirePackage{l3keys2e}
\ProcessKeysOptions{cache}


% Setting up lazy execution and
% selecting of executing after reading of aux file
% if cache option has been used
\bool_if:NTF \g__cache_cache_bool
  {
    %% Writing things (at one go) to aux file at end of document:
    \cs_new:Npn \__cache_dump_auxfile:n
      {
        \clist_gput_right:Nn \g__cache_dump_auxfile_clist
      }
    \cs_generate_variant:Nn \__cache_dump_auxfile:n { x }

    \cs_new:Npn \__cache_dump_cache:n 
      {
        \clist_gput_right:Nn \g__cache_dump_cache_clist
      }
    \cs_generate_variant:Nn \__cache_dump_cache:n { V }


    \cs_new:Npn \__cache_write_auxout:n
      {
        \iow_now:cn { @auxout }
      }
    \cs_generate_variant:Nn \__cache_write_auxout:n { x }

    %%% Handles dumping data to aux file at end of document
    \hook_gput_code:nnn { enddocument } { cache }
      {
        \clist_map_function:NN \g__cache_dump_auxfile_clist
          \__cache_write_auxout:n
        
        \__cache_write_auxout:n
          {
            \csname tl_gput_right:cn \endcsname
              {
                g__cache_lazy_auxfile_tl
              }
          }
        \__cache_write_auxout:x { \str_use:N \c_left_brace_str }

        \clist_map_function:NN \g__cache_dump_cache_clist
          \__cache_write_auxout:n

        \__cache_write_auxout:x { \str_use:N \c_right_brace_str }
      }

    %%% Writes the current cache version into aux file
    \__cache_dump_auxfile:x
      {
        \ExplSyntaxOn
        \int_gset:Nn \exp_not:N \g__cache_cache_version_aux_int
          {
            \int_use:N \g__cache_cache_version_document_int
          }
        \ExplSyntaxOff
      }

    %%% Executing something lazily at beginning of document
    %%% Lazy code only gets executed if auxfile version is older than document
    \cs_new:Npn \__cache_lazy:n
      {
        \tl_gput_right:Nn \g__cache_lazy_document_tl 
      }

    %%% Caching things. Handles writing and reading to aux file
    %%% and makes code available in the next run of LaTeX
    \cs_new:Npn \__cache_cache:n #1
      {
        \tl_set:Nn \l_tmpa_tl
          {
            { #1 }
          }
        \regex_replace_all:nnN { \cP\# } { \cO\# } \l_tmpa_tl
        \__cache_dump_cache:V \l_tmpa_tl
      }

    %%% This handles loading either the cached definitions
    %%% from last run or executing the lazy definitions from the current run
    %%% after loading the aux file
    \hook_gput_code:nnn { begindocument } { cache }
      {
        \int_compare:nNnTF
          \g__cache_cache_version_aux_int < \g__cache_cache_version_document_int
            {
              \tl_use:N \g__cache_lazy_document_tl
            }
            {
              \tl_use:N \g__cache_lazy_auxfile_tl
            }
      }
  }
  {
    \cs_set_eq:NN \__cache_lazy:n \use:n
    \cs_set_eq:NN \__cache_cache:n \use_none:n
  }

\cs_new:Npn \__cached_new_document_command:nnn #1 #2 #3
  {
    \NewDocumentCommand{#1}{#2}{#3}
    \__cache_cache:n
      {
        \csname __cached_new_document_command:nnn \endcsname { #1 } { #2 } { #3 }
      }
  }

\NewDocumentCommand{\DeclareCachedDocumentCommand}{mmm}
  {
    \__cache_lazy:n
      {
        \__cached_new_document_command:nnn{#1}{#2}{#3}
      }
  }
