docs: def dzn2dict(dzn, *, rebase_arrays=True, types=None, return_enums=False):
      """Parses a dzn string or file into a dictionary of variable assignments.
  
      Parameters
      ----------
      dzn : str
          A dzn content string or a path to a dzn file.
      rebase_arrays : bool
          Whether to return arrays as zero-based lists or to return them as
          dictionaries, preserving the original index-sets.
      types : dict
          Dictionary of variable types. Types can either be dictionaries, as
          returned by the ``minizinc --model-types-only``, or strings containing a
          type in dzn format. If the type is a string, it can either be the name
          of an enum type or one of the following: ``bool``, ``int``, ``float``,
          ``enum``, ``set of <type>``, ``array[<index_sets>] of <type>``. The
          default value for ``var_types`` is ``None``, in which case the type of
          most dzn assignments will be inferred automatically from the value. Enum
          values can only be parsed if their respective types are available.
      return_enums : bool
          Whether to return the parsed enum types included in the dzn content.
  
      Returns
      -------
      dict
          A dictionary containing the variable assignments parsed from the
          input file or string.
      """
      dzn_ext = os.path.splitext(dzn)[1]
      if dzn_ext == '.dzn':
          with open(dzn) as f:
              dzn = f.read()
  
      var_types = None
      if types:
          var_types = {}
          for var, var_type in types.items():
              if isinstance(var_type, str):
                  var_types[var] = _to_var_type(var, var_type)
              elif isinstance(var_type, dict):
                  var_types[var] = var_type
              else:
                  err = 'Type of variable {} must be a string or a dict.'
                  raise ValueError(err.format(var))
  
      enum_types = None
      if var_types:
          enum_types = []
          for var, var_type in var_types.items():
              if 'enum_type' in var_type and var_type['enum_type'] == var:
                  enum_types.append(var)
  
      var_list = []
      dzn = _comm_p.sub('\n', dzn)
      stmts = _stmt_p.findall(dzn)
      for stmt in stmts:
          var_m = _var_p.match(stmt)
          if var_m:
              var = var_m.group('var')
              val = var_m.group('val')
              var_list.append((var, val))
          else:
              raise ValueError(
                  'Unsupported parsing for statement:\n{}'.format(repr(stmt))
              )
  
      enums = None
      if enum_types:
          enums = {}
          remaining = []
          while len(var_list) > 0:
              var, val = var_list.pop(0)
              if var in enum_types:
                  enum = None
                  enum_m = _enum_p.match(val)
                  if enum_m:
                      vals = enum_m.group('vals').strip()
                      if vals:
                          enum_vals = _parse_enum_vals(vals.split(','))
                          enum = IntEnum(
                              var, {v: i + 1 for i, v in enumerate(enum_vals)}
                          )
                  if enum is None:
                      raise ValueError(
                          'Cannot parse enum type \'{} = {}\'.'.format(var, val)
                      )
                  enums[var] = enum
              else:
                  remaining.append((var, val))
          var_list = remaining
  
      assign = {}
      for var, val in var_list:
          var_type = None
          if var_types:
              var_type = var_types.get(var, None)
          assign[var] = parse_value(
              val, var_type=var_type, enums=enums, rebase_arrays=rebase_arrays
          )
  
      if return_enums and enums:
          assign.update(enums)
  
      return assign