The InputStream Interface in Swift

On this page:

Initializing an InputStream in Swift

The InputStream class provides two initializers:

Swift
public class InputStream {
   public convenience init(communicator: Communicator, bytes: Foundation.Data) {...}
   public required init(communicator: Communicator, encoding: EncodingVersion, bytes: Foundation.Data) {...}
} 

These initializers accept up to 3 parameters:

  • A communicator instance
  • An encoding version
  • A Foundation.Data object containing the encoded data that you intend to decode

If you omit an encoding version, the stream uses the default encoding version of the communicator or the most recent encoding version.

Extracting from an InputStream in Swift

InputStream provides a number of read methods that allow you to extract Slice types from the stream.

For example, you can extract a boolean and a sequence of strings from a stream as follows:

Swift
var data: Foundation.Data = ...
let in = Ice.InputStream(communicator: communicator, data: data)
let b: Bool = try in.read()
let seq: [String] = try in.read()

Here are the methods for extracting data from a stream:

Swift
public extension InputStream {
    /// Reads a numeric value from the stream.
    func read<Element>() throws -> Element where Element: StreamableNumeric

    /// Reads an optional numeric value from the stream.
    func read<Element>(tag: Int32) throws -> Element? where Element: StreamableNumeric

    /// Reads a sequence of numeric values from the stream.
    func read<Element>() throws -> [Element] where Element: StreamableNumeric

    /// Reads an optional sequence of numeric values from the stream.
    func read<Element>(tag: Int32) throws -> [Element]? where Element: StreamableNumeric

    /// Reads a byte from the stream.
    func read() throws -> UInt8

    /// Reads a sequence of bytes from the stream.
    func read() throws -> [UInt8]

    /// Reads a sequence of bytes from the stream.
    func read() throws -> Data

    /// Reads an optional sequence of bytes from the stream.
    func read(tag: Int32) throws -> Data?

    /// Reads a boolean value from the stream.
    func read() throws -> Bool

    /// Reads an optional boolean value from the stream.
    func read(tag: Int32) throws -> Bool?

    /// Reads a sequence of boolean value from the stream.
    func read() throws -> [Bool]

    /// Reads an optional sequence of boolean value from the stream.
    func read(tag: Int32) throws -> [Bool]?

    /// Reads a size from the stream.
    func readSize() throws -> Int32

    /// Reads a sequence size from the stream and ensures the stream has enough
    /// bytes for `size` elements, where each element's size is at least minSize.
    func readAndCheckSeqSize(minSize: Int) throws -> Int

    /// Reads an enumerator from the stream, as a byte.
    func read(enumMaxValue: Int32) throws -> UInt8

    /// Reads an enumerator from the stream, as a Int32.
    func read(enumMaxValue: Int32) throws -> Int32

    /// Reads a string from the stream.
    func read() throws -> String

    /// Reads an optional string from the stream.
    func read(tag: Int32) throws -> String?

    /// Reads a sequence of strings from the stream.
    func read() throws -> [String]

    /// Reads an optional sequence of strings from the stream.
    func read(tag: Int32) throws -> [String]?

    /// Reads a proxy from the stream.
    func read(_: ObjectPrx.Protocol) throws -> ObjectPrx?

    /// Reads an optional proxy from the stream.
    func read(tag: Int32, type _: ObjectPrx.Protocol) throws -> ObjectPrx?

    /// Reads a value from the stream.
    func read(cb: ((Value?) throws -> Void)?) throws

    /// Reads an optional value from the stream.
    func read(tag: Int32, cb: ((Value?) throws -> Void)?) throws
}

The read methods are overloaded to allow you to extract all of primitive types, as well as sequences of primitive types. The Slice to Swift compiler generate additional read overloads for user-defined types. The remaining methods have the following semantics:

  • func readSize() throws -> Int32
    The Ice encoding has a compact representation to indicate size. This method extracts a size and returns it as an integer.
  • func readAndCheckSeqSize(minSize: Int) throws -> Int
    Like readSize, this method reads a size and returns it, but also verifies that there is enough data remaining in the buffer to successfully unmarshal the elements of the sequence. The minWireSize parameter indicates the smallest possible on-the-wire representation of a single sequence element. If the buffer contains insufficient data to unmarshal the sequence, the method throws UnmarshalOutOfBoundsException.
  • void throwException()
    This method extracts a user exception from the stream and throws it. If the stored exception is of an unknown type, the method attempts to extract and throw a less-derived exception. If this fails, it throws UnknownUserException with for the 1.1 encoding and  UnmarshalOutOfBoundsException for the 1.0 encoding.

  • func startSlice() throws -> String
    func endSlice() throws
    func skipSlice() throws
    Start, end, and skip a slice. These methods are used when manually extracting the slices of a class instance or user exception. The startSlice method returns the type ID of the next slice, which may be an empty string depending on the format used to encode the instance or exception.
  • func startValue()
    func endValue(preserve: Bool) throws -> SlicedData?
    The startValue method must be called prior to reading the slices of a class instance. The endValue method must be called after all slices have been read. Pass true to endValue in order to preserve the slices of any unknown more-derived types, or false to discard the slices. If preserve is true and the stream actually preserved any slices, the return value of endValue is a non-nil SlicedData object that encapsulates the slice data. If the caller later wishes to forward the instance with any preserved slices intact, it must supply this SlicedData object to the output stream.
  • func startException()
    func endException(preserve: Bool) throws -> SlicedData?
    The startException method must be called prior to reading the slices of an exception. The endException method must be called after all slices have been read. Pass true to endException in order to preserve the slices of any unknown more-derived types, or false to discard the slices. If preserve is true and the stream actually preserved any slices, the return value of endException is a non-nil SlicedData object that encapsulates the slice data. If the caller later wishes to forward the exception with any preserved slices intact, it must supply this SlicedData object to the output stream.
  • func startEncapsulation() throws -> EncodingVersion
    func endEncapsulation() throws
    func skipEncapsulation() throws -> EncodingVersion
    Start, end, and skip an encapsulation, respectively. The startEncapsulation and skipEncapsulation methods return the encoding version used to encode the contents of the encapsulation.
  • func skipEmptyEncapsulation() throws -> EncodingVersion
    Skips an encapsulation that is expected to be empty and returns its encoding version. The stream raises EncapsulationException if the encapsulation is not empty.
  • func readPendingValues() throws
    With encoding version 1.0, an application must call this method after all other data has been extracted, but only if class instances were encoded. This method extracts the state of class instances and invokes their corresponding callback objects (see readValue). This method is no-op with encoding version 1.1.
  • func skip(_ count: Int) throws
    Skips the given number of bytes.
  • func skipSize() throws
    Reads a size at the current position and skips that number of bytes.
  • func readOptional(tag: Int32, expectedFormat: OptionalFormat) throws -> Bool
    Returns true if an optional value with the given tag and format is present, or false otherwise. If this method returns true, the data associated with that optional value must be read next. Optional values must be read in order by tag from least to greatest. The OptionalFormat enumeration is defined as follows:

    C#
    enum OptionalFormat: UInt8 {
        case F1 = 0
        case F2 = 1
        case F4 = 2
        case F8 = 3
        case Size = 4
        case VSize = 5
        case FSize = 6
        case Class = 7
    ...
    }

    Refer to the encoding discussion for more information on the meaning of these values.

InputStream Extensions

The InputStream class provides all of the low-level methods necessary for decoding Ice types. However, it would be tedious and error-prone to manually decode complex Ice-types such as classes, structures, and enumerated types. the Slice compiler generates extensions to the InputStream for decoding complex Ice types.

We will use the following Slice definitions to demonstrate the language mapping:

Slice
module M
{
    struct S
    {
        ...
    }
    enum E { ... }
    class C
    {
        ...
    }
    interface I
    {
        ...
    }
}

The Slice compiler generates the corresponding InputStream extension shown below:

Swift
/// An Ice.InputStream extension to read S structured values from the stream.
public extension Ice.InputStream {
    /// Read a `S` structured value from the stream.
    func read() throws -> S { ... }
    /// Read an optional `S?` structured value from the stream.
    func read(tag: Swift.Int32) throws -> S? { ... }
}


/// An Ice.InputStream extension to read E enumerated values from the stream.
public extension Ice.InputStream {
    /// Read an enumerated value.
    func read() throws -> E
    /// Read an optional enumerated value from the stream.
    func read(tag: Swift.Int32) throws -> E?
}


/// Extension to Ice.InputStream class to support reading proxy of type IPrx.
public extension Ice.InputStream {
    /// Extracts a proxy from the stream. The stream must have been initialized with a communicator.
    func read(_ type: IPrx.Protocol) throws -> IPrx? { ... }
    /// Extracts a proxy from the stream. The stream must have been initialized with a communicator.
    func read(tag: Swift.Int32, type: IPrx.Protocol) throws -> IPrx? { ... }
}

No additional code is generated for unmarshaling instances of class types, such as type C that we defined above. Applications should use InputStream.read to extract class instances.


See Also