/**
 * Encode and decode MessagePack frames in Effect channels.
 *
 * MessagePack is a compact binary serialization format for protocols and
 * storage layers that expect bytes rather than JSON text, such as RPC
 * transports, socket streams, caches, or database columns. This module provides
 * raw channel helpers for already-agreed value shapes and schema helpers for
 * validating, transforming, or decoding domain values at the boundary.
 *
 * **Mental model**
 *
 * - Each input value passed to {@link encode} becomes one MessagePack byte array
 * - {@link decode} can receive arbitrary byte chunks; incomplete frames are
 *   buffered until enough bytes arrive
 * - Schema helpers run Effect schema encoding before packing and schema decoding
 *   after unpacking
 *
 * **Common tasks**
 *
 * - Pack values into bytes: {@link encode}
 * - Unpack byte chunks into values: {@link decode}
 * - Encode or decode domain values with schemas: {@link encodeSchema}, {@link decodeSchema}
 *
 * **Gotchas**
 *
 * - MessagePack preserves binary data better than JSON, but it is not a schema;
 *   use schema helpers when runtime validation matters
 * - Packing failures surface as {@link MsgPackError}; schema failures surface as
 *   `SchemaError` before or after the binary boundary
 * - Decoding expects complete MessagePack documents over time, not arbitrary
 *   byte payloads with out-of-band framing
 *
 * @since 4.0.0
 */
import { Packr, Unpackr } from "msgpackr";
import * as Msgpackr from "msgpackr";
import * as Arr from "../../Array.js";
import * as Channel from "../../Channel.js";
import * as ChannelSchema from "../../ChannelSchema.js";
import * as Data from "../../Data.js";
import * as Effect from "../../Effect.js";
import { dual } from "../../Function.js";
import * as Option from "../../Option.js";
import * as Predicate from "../../Predicate.js";
import * as Schema from "../../Schema.js";
import * as Issue from "../../SchemaIssue.js";
import * as Transformation from "../../SchemaTransformation.js";
const MsgPackErrorTypeId = "~effect/encoding/MsgPack/MsgPackError";
/**
 * Error raised when MessagePack encoding or decoding fails.
 *
 * **Details**
 *
 * The `kind` field identifies whether the failure happened while packing or
 * unpacking, and `cause` preserves the original error.
 *
 * @category errors
 * @since 4.0.0
 */
export class MsgPackError extends /*#__PURE__*/Data.TaggedError("MsgPackError") {
  /**
   * Marks this value as a MessagePack encoding or decoding error for runtime guards.
   *
   * @since 4.0.0
   */
  [MsgPackErrorTypeId] = MsgPackErrorTypeId;
  /**
   * Uses the failed MessagePack operation as the public message.
   *
   * @since 4.0.0
   */
  get message() {
    return this.kind;
  }
}
/**
 * Creates a channel that encodes non-empty chunks of values as MessagePack byte
 * arrays.
 *
 * **Details**
 *
 * The channel fails with `MsgPackError` when any value cannot be packed.
 *
 * @category constructors
 * @since 4.0.0
 */
export const encode = () => Channel.fromTransform((upstream, _scope) => Effect.sync(() => {
  const packr = new Packr();
  return Effect.flatMap(upstream, chunk => {
    try {
      return Effect.succeed(Arr.map(chunk, item => packr.pack(item)));
    } catch (cause) {
      return Effect.fail(new MsgPackError({
        kind: "Pack",
        cause
      }));
    }
  });
}));
/**
 * Creates a MessagePack encoder channel for values of a schema.
 *
 * **Details**
 *
 * Values are first encoded with the schema and then packed as MessagePack bytes,
 * so the channel can fail with either schema errors or `MsgPackError`.
 *
 * @category constructors
 * @since 4.0.0
 */
export const encodeSchema = schema => () => Channel.pipeTo(ChannelSchema.encode(schema)(), encode());
/**
 * Creates a channel that decodes MessagePack byte chunks into values.
 *
 * **Details**
 *
 * Incomplete frames are buffered across chunks, and invalid MessagePack data
 * fails with `MsgPackError`.
 *
 * @category constructors
 * @since 4.0.0
 */
export const decode = () => Channel.fromTransform((upstream, _scope) => Effect.sync(() => {
  const unpackr = new Unpackr();
  let incomplete = undefined;
  return Effect.flatMap(upstream, function loop(chunk) {
    const out = Arr.empty();
    for (let i = 0; i < chunk.length; i++) {
      let buf = chunk[i];
      if (incomplete !== undefined) {
        const prev = buf;
        buf = new Uint8Array(incomplete.length + buf.length);
        buf.set(incomplete);
        buf.set(prev, incomplete.length);
        incomplete = undefined;
      }
      try {
        out.push(...unpackr.unpackMultiple(buf));
      } catch (cause) {
        const error = cause;
        if (error.incomplete) {
          incomplete = buf.subarray(error.lastPosition);
          if (error.values) {
            out.push(...error.values);
          }
        } else {
          return Effect.fail(new MsgPackError({
            kind: "Unpack",
            cause
          }));
        }
      }
    }
    return Arr.isReadonlyArrayNonEmpty(out) ? Effect.succeed(out) : Effect.flatMap(upstream, loop);
  });
}));
/**
 * Creates a MessagePack decoder channel for values of a schema.
 *
 * **Details**
 *
 * The channel unpacks bytes into unknown values and then decodes each value with
 * the schema.
 *
 * @category constructors
 * @since 4.0.0
 */
export const decodeSchema = schema => () => Channel.pipeTo(decode(), ChannelSchema.decodeUnknown(schema)());
/**
 * Wraps a bidirectional byte channel with MessagePack encoding and decoding.
 *
 * **Details**
 *
 * Outgoing values are packed as MessagePack bytes before reaching the wrapped
 * channel, and incoming bytes are unpacked into values.
 *
 * @category combinators
 * @since 4.0.0
 */
export const duplex = self => encode().pipe(Channel.pipeTo(self), Channel.pipeTo(decode()));
/**
 * Wraps a bidirectional byte channel with schema-aware MessagePack encoding and
 * decoding.
 *
 * **Details**
 *
 * Values sent to the wrapped channel are encoded with `inputSchema` and packed
 * as MessagePack bytes; bytes received from it are unpacked and decoded with
 * `outputSchema`.
 *
 * @category combinators
 * @since 4.0.0
 */
export const duplexSchema = /*#__PURE__*/dual(2, (self, options) => ChannelSchema.duplexUnknown(duplex(self), options));
/**
 * Schema for decoding MessagePack bytes into values and encoding values back to
 * MessagePack bytes.
 *
 * **Details**
 *
 * MessagePack codec failures are converted to `InvalidValue` schema issues.
 *
 * @category schemas
 * @since 4.0.0
 */
export const transformation = /*#__PURE__*/Transformation.transformOrFail({
  decode(e, _options) {
    try {
      return Effect.succeed(Msgpackr.decode(e));
    } catch (cause) {
      return Effect.fail(new Issue.InvalidValue(Option.some(e), {
        message: Predicate.hasProperty(cause, "message") ? String(cause.message) : String(cause)
      }));
    }
  },
  encode(t, _options) {
    try {
      return Effect.succeed(Msgpackr.encode(t));
    } catch (cause) {
      return Effect.fail(new Issue.InvalidValue(Option.some(t), {
        message: Predicate.hasProperty(cause, "message") ? String(cause.message) : String(cause)
      }));
    }
  }
});
/**
 * Builds a schema that stores values as MessagePack bytes.
 *
 * **Details**
 *
 * The resulting schema decodes `Uint8Array` payloads with MessagePack and the
 * provided schema, and encodes values back to MessagePack bytes.
 *
 * @category schemas
 * @since 4.0.0
 */
export const schema = schema => Schema.Uint8Array.pipe(Schema.decodeTo(schema, transformation));
//# sourceMappingURL=Msgpack.js.map