Example implementation of a cloneable interface (assuming its located in
 * `internal/my_interface.js`):
 *
 * ```
 * class MyInterface {
 *   constructor(...args) {
 *     markTransferMode(this, true);
 *     this.args = args;
 *   }
 *   [kDeserialize](data) {
 *     this.args = data.args;
 *   }
 *   [kClone]() {
 *     return {
 *        data: { args: this.args },
 *        deserializeInfo: 'internal/my_interface:MyInterface',
 *     }
 *   }
 * }
 *
 * module.exports = {
 *   MyInterface,
 * };
 * ```
 * @param {object} obj Host objects that can be either cloned or transferred.
 * @param {boolean} [cloneable] if the object can be cloned and `@@kClone` is
 *                              implemented.
 * @param {boolean} [transferable] if the object can be transferred and
 *                                 `@@kTransfer` is implemented.
 */
function markTransferMode(obj, cloneable = false, transferable = false) {
  if ((typeof obj !== 'object' && typeof obj !== 'function') || obj === null)
    return;  // This object is a primitive and therefore already untransferable.
  let mode = kDisallowCloneAndTransfer;
  if (cloneable) mode |= kCloneable;
  if (transferable) mode |= kTransferable;
  obj[transfer_mode_private_symbol] = mode;
}


webidl.converters.StructuredSerializeOptions = webidl
  .createDictionaryConverter(
    [
      {
        key: 'transfer',
        converter: webidl.converters['sequence<object>'],
        defaultValue: () => [],
      },
    ],
  );

function structuredClone(value, options) {
  if (arguments.length === 0) {
    throw new ERR_MISSING_ARGS('The value argument must be specified');
  }

  const idlOptions = webidl.converters.StructuredSerializeOptions(
    options,
    {
      __proto__: null,
      prefix: "Failed to execute 'structuredClone'",
      context: 'Options',
    },
  );

  const serializedData = nativeStructuredClone(value, idlOptions);
  return serializedData;
}

module.exports = {
  markTransferMode,
  setup,
  structuredClone,
  kClone: messaging_clone_symbol,
  kDeserialize: messaging_deserialize_symbol,
  kTransfer: messaging_transfer_symbol,
  kTransferList: messaging_transfer_list_symbol,
};
