makeInnerEncode = (encodeStringSuffix, encodeArray, options) => {
  const {
    encodeRemotable: unsafeEncodeRemotable,
    encodePromise: unsafeEncodePromise,
    encodeError: unsafeEncodeError,
    verifyEncoding = () => {},
  } = options;
  const encodeRemotable = makeEncodeRemotable(
    unsafeEncodeRemotable,
    verifyEncoding,
  );
  const encodePromise = makeEncodePromise(unsafeEncodePromise, verifyEncoding);
  const encodeError = makeEncodeError(unsafeEncodeError, verifyEncoding);

  const innerEncode = passable => {
    if (isErrorLike(passable)) {
      // We pull out this special case to accommodate errors that are not
      // valid Passables. For example, because they're not frozen.
      // The special case can only ever apply at the root, and therefore
      // outside the recursion, since an error could only be deeper in
      // a passable structure if it were passable.
      //
      // We pull out this special case because, for these errors, we're much
      // more interested in reporting whatever diagnostic information they
      // carry than we are about reporting problems encountered in reporting
      // this information.
      return encodeError(passable, innerEncode);
    }
    const passStyle = passStyleOf(passable);
    switch (passStyle) {
      case 'null': {
        return 'v';
      }
      case 'undefined': {
        return 'z';
      }
      case 'number': {
        return encodeBinary64(passable);
      }
      case 'string': {
        return `s${encodeStringSuffix(passable)}`;
      }
      case 'boolean': {
        return `b${passable}`;
      }
      case 'bigint': {
        return encodeBigInt(passable);
      }
      case 'remotable': {
        return encodeRemotable(passable, innerEncode);
      }
      case 'error': {
        return encodeError(passable, innerEncode);
      }
      case 'promise': {
        return encodePromise(passable, innerEncode);
      }
      case 'symbol': {
        // Strings and symbols share encoding logic.
        const name = nameForPassableSymbol(passable);
        assert.typeof(name, 'string');
        return `y${encodeStringSuffix(name)}`;
      }
      case 'copyArray': {
        return encodeArray(passable, innerEncode);
      }
      case 'byteArray': {
        return encodeByteArray(passable, innerEncode);
      }
      case 'copyRecord': {
        return encodeRecord(passable, encodeArray, innerEncode);
      }
      case 'tagged': {
        return encodeTagged(passable, encodeArray, innerEncode);
      }
      default: {
        throw Fail`a ${q(passStyle)} cannot be used as a collection passable`;
      }
    }
  };
  return innerEncode;
}
@param {(str: string) => string} encodeStringSuffix
@param {(arr: unknown[], encodeRecur: (p: Passable) => string) => string} encodeArray
@param {Required<EncodeOptions> & {verifyEncoding?: (encoded: string, label: string) => void}} options
@returns {(p: Passable) => string}