(*---------------------------------------------------------------------------*
  INTERFACE  cf_message.mli

  Copyright (c) 2002-2006, James H. Woodyatt
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

    Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

    Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in
    the documentation and/or other materials provided with the
    distribution

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  OF THE POSSIBILITY OF SUCH DAMAGE. 
 *---------------------------------------------------------------------------*)

(** Functional message buffer chains. *)

(** {6 Overview}

    This module implements convenience functions useful when manipulating
    lists of substrings that represent portable inter-process communication
    messages.  A list of substrings is very much like the "mbuf" chain commonly
    found in network protocol stacks, and this module facilitates composing
    and manipulating messages in this way.
*)

(** {6 Types} *)

(** The type of messages, i.e. a list of substrings (a string, the position of
    the first character in the substring, and the length of the substring).
*)
type substring = string * int * int and t = substring list

(** {6 Functions} *)

(** Use [normalize m] to discard empty substrings from the list.  Raises
    [Invalid_arg] if any of the substrings have a negative length or which
    specify invalid substrings of the string component of the triple.
*)
val normalize: t -> t

(** Use [create s] to obtain a new message composed of a flattened message
    containing the string [s].  Returns the empty list when the string is the
    empty string.
*)
val create: string -> t

(** Use [length m] to compute the length of the message [m]. *)
val length: t -> int

(** Use [contents m] to create a new string containing the entire text of the
    message [m].
*)
val contents: t -> string

(** Use [copy m] to create a new message with a deep copy of the contents of
    [m], i.e. it is equivalent to [create (contents m)].
*)
val copy: t -> t

(** Use [flatten m] to reduce a message list of two or more substrings to a
    single substring.  If [m] is already a single substring or the empty list,
    then [m] itself is returned.  Otherwise, the result is the same as what
    [copy m] would return.
*)
val flatten: t -> t

(** Use [split ~pos m] to return two new messages, the first containing all the
    text in message [m] before the position [pos], and the second containing
    all the remaining text in message [m].  The strings themselves are not
    copied; only the list of substrings is manipulated.  Raises
    [Invalid_argument] if the position is negative or beyond the length of the
    message.
*)
val split: pos:int -> t -> t * t

(** Use [truncate ~pos m] to return a new message containing all the text in
    message [m] before the position [pos].  The strings themselves are not
    copied; only the list of substrings is manipulated.  Raises
    [Invalid_argument] if the position is negative or beyond the length of the
    message.
*)
val truncate: pos:int -> t -> t

(** Use [shift ~pos m] to return a new message with all the text in message [m]
    before the position [pos] removed.  This strings themselves are not copied;
    only the list of substrings is manipulated.  Raises [Invalid_argument] if
    the position is negative or beyond the length of the message.
*)
val shift: pos:int -> t -> t

(** Use [insert ~pos ~m m1] to return a new message with all the text in
    message [m] inserted into the message [m1] at the position [pos].  The
    strings themselves are not copied; only the list of substrings is
    manipulated.  Raises [Invalid_argument] if the position is negative or
    beyond the length of the message.
*)
val insert: pos:int -> m:t -> t -> t

(** Use [push m q] to push the message [m] into the [A] end of the substring
    queue [q].
*)
val push: t -> substring Cf_deque.t -> substring Cf_deque.t

(** Use [pop ~len q] to pop a message of length no larger than [len] from the
    [B] end of the substring deque [q].  The message and the remainder of the
    deque are returned.
*)
val pop: len:int -> substring Cf_deque.t -> t * substring Cf_deque.t

(** Use [shiftq ~len q] to discard the first [len] octets from the [B] end of
    the substring deque [q].  The remainder of the deque is returned.
*)
val shiftq: len:int -> substring Cf_deque.t -> substring Cf_deque.t

(** Use [drain q] to convert the entire substring deque [q] into a message. *)
val drain: substring Cf_deque.t -> t

(** Use [drain_seq q] to convert the substring deque [q] into a character
    sequence.  If [?x] is provided then evaluating the sequence past the last
    character in the message raises the exception.  (This is more efficient
    than applying [Cf_seq.sentinel] to the result.)
*)
val drain_seq: ?x:exn -> substring Cf_deque.t -> char Cf_seq.t

(** Use [to_seq m] to obtain the sequence of characters in message [m].
    The message is immediately normalized with [normalize m].  If [?x] is
    provided then evaluating the sequence past the last character in the
    message raises the exception.  (This is more efficient than applying
    [Cf_seq.sentinel] to the result.)
*)
val to_seq: ?x:exn -> t -> char Cf_seq.t

(** [to_function m] returns a function that returns successive characters from
    the message [m] each time it is called, until it raises [x] when there are
    no more characters.  If [x] is not provided, then [End_of_file] is raised.
*)
val to_function: ?x:exn -> t -> (unit -> char)

(**/**)

(** The same as [push m q] except the message is assumed to be normalized
    already.
*)
val unsafe_push: t -> substring Cf_deque.t -> substring Cf_deque.t

(** Shifts one character off the start of the text of the message.  Assumes
    the message is normalized. *)
val unsafe_shift1: t -> t

(** The same as [to_seq ?x m] except the message is assumed to be normalized
    already.
*)
val unsafe_to_seq: ?x: exn -> t -> char Cf_seq.t

(** The same as [to_function ?x m] except the message is assumed to be
    normalized already.
*)
val unsafe_to_function: ?x:exn -> t -> (unit -> char)

(*--- End of File [ cf_message.mli ] ---*)
