“How do you describe endianness (or byte-order) as a type in your code?”
This proposal is a simple answer to that simple question.
You may often take byte-order into account when you get involved in, for example, stream programming. While network byte-order is defined as big endian, you may have to handle some other stream whose endian is unknown in advance. In such case, you want a type that identifies endianness to write code like let thatEndian = ByteOrder.littleEndian.
Note: This proposal is inspired by the other proposal given the title "Unicode Processing APIs" which includes such a type to be introduced. This proposal focuses on only that type.
CoreFoundation has a such type that represents endianness, and its related definitions look like the following from Swift.
public struct __CFByteOrder: RawRepresentable, Equatable {
public init(_ rawValue: UInt32)
public init(rawValue: UInt32)
public var rawValue: UInt32
}
public var CFByteOrderUnknown: __CFByteOrder { get }
public var CFByteOrderLittleEndian: __CFByteOrder { get }
public var CFByteOrderBigEndian: __CFByteOrder { get }
public typealias CFByteOrder = CFIndex
public func CFByteOrderGetCurrent() -> CFByteOrderImagine that you have to implement a function that detects byte-order of some stream for UTF-16.
Such a function could appear to be as follows if you use directly __CFByteOrder.
import CoreFoundation
func detectByteOrder(_ stream: some Sequence) -> __CFByteOrder? { /* ... */ }The issues here are:
__CFByteOrderis double-underscored. That means this type might not be officially public.CFByteOrder{Unknwon|LittleEndian|BigEndian}is a global variable, not anenumcase.- You can use
CFByteOrderinstead, but it is atypealiasofCFIndexwhich is just an integer. - There are some platforms on which
CoreFoundationis unavailable from Swift in the first place.
The way to solve the issues is simple. It's to add a type for byte-order.
As descriged above, such kind of type is proposed as a part of the other proposal, but is not realized yet.
The type would be implemented as follows if it corresponds to current CF* definitions described above.
/// A type that identifies byte order.
@frozen
public enum ByteOrder: Equatable, Sendable {
/// Multi-byte values are stored with the least-significant bytes stored first.
/// Pentium CPUs are little endian.
case littleEndian
/// Multi-byte values are stored with the most-significant bytes stored first.
/// PowerPC CPUs are big endian.
case bigEndian
/// The byte order of the current computer.
public static var current: ByteOrder! {
#if _endian(little)
return .littleEndian
#elseif _endian(big)
return .bigEndian
#else
return nil
#endif
}
}Then, you can substitute ByteOrder for __CFByteOrder.
There are no source compatibility concerns because just a new type is added by this proposal.
Adding the new type does not affect ABI.
This feature can be freely adopted and un-adopted in source code with no deployment constraints and without affecting source or ABI compatibility.
Sorry for saying it again, but this proposal is inspired by the other proposal that contains the feature to add this kind of type. This proposal could be a part of that feature.
Furthermore, of course, ByteOrder is so highly versatile (in other words, so simple) that there's the possibility of being adopted by any other features.
We can choose Endianness or other names instead of ByteOrder.
However, ByteOrder is preferred since the name of the existing type in CoreFoundation comprises "byte-order".
There could be also some alternative names for static var current: ByteOrder { get } such as host or native, while, same as above, current derives from CFByteOrderGetCurrent.
There are unusual orderings that are generically called "middle-endian" or "mixed-endian". Swift doesn't currently support such architectures.
We can adopt ByteOrder instead of ByteOrder! for the type of current if Swift decides never to support such rare endians forever. Otherwise, the type should be Optional.
For example, types that conform to FixedWidthIntegers have initializers init(bigEndian: Self) and init(littleEndian: Self), and properties var bigEndian: Self { get } and var littleEndian: Self. In case of using that APIs, you don't have to know the host byte order. Namely we may omit a static property that enables to get "current" byte order.
ByteOrder type should conform to RawRepresentable where its RawValue is UInt32 if we let it compatible with __CFByteOrder.
The change by this proposal is so small that it can be a part of other evolution. Indeed, as described above, this proposal is inspired by the other pitch. On the other hand, there are points to discuss about this type, i.g. alternatives mentioned in this section. That's why we should discuss this small change separately from other proposals.
For example, swift-foundation, swift-syntax and swift-nio have their own enum Endianness 1 2 3. Although you can import them, they are not compatible with each other. Generally speaking, it is not desirable that definitions for the same purpose are scattered. In conclusion, this type should be defined in the standard library.
Footnotes
-
https://github.com/apple/swift-foundation/blob/660f795ad82fe4e5f8a349006a756c09b19d3e16/Sources/FoundationEssentials/String/String%2BEndianAdaptorSequence.swift#L13-L33 ↩
-
https://github.com/swiftlang/swift-syntax/blob/fc03febda6a46b9d10b65af64724627c30339bd9/Sources/SwiftIfConfig/BuildConfiguration.swift#L15-L23 ↩
-
https://github.com/apple/swift-nio/blob/a4e0a13c8b8d5b63e81be2b672230a334e78ed44/Sources/NIOCore/ByteBuffer-int.swift#L173-L189 ↩