Oh, of course. I think I knew that once. I've been a little out of it. Thank you!
So I could have an InlineArray that offers a Span? Can I offer a Span of an underlying C Array? I'm going to have to play with that, but now that's probably OT...
I'm not sure you can, currently, offer a Span of a C array (as Span has no public initializers yet), but I think you should be able to get a Span from an InlineArray.
With the recent proposal SE-0447 Span: Safe Access to Contiguous Storage who defines a safe abstraction over viewing contiguous storage, it would make sense to define API on InlineArray to be able to get one of these Spans. However, the proposal states that:
We could provide withSpan() and withBytes() closure-taking functions as safe replacements for the existing withUnsafeBufferPointer() and withUnsafeBytes() functions. We could also also provide lifetime-dependent span or bytes properties. ... Of these, the closure-taking functions can be implemented now, but it is unclear whether they are desirable. The lifetime-dependent computed properties require lifetime annotations, as initializers do. We are deferring proposing these extensions until the lifetime annotations are proposed.
All of which is exactly true for the current InlineArray type. We could propose a withSpan style API now, but it's unclear if that's what we truly want vs. a computed property that returns the span which requires lifetime annotation features. For now, we're deferring such API until a lifetime proposal is proposed and accepted.
But if the underlying type conforms to BitwiseCopyable one could maybe probably jump the gun a bit behind the scenes...
While there are no official initializers yet for Span, SE-0456 (announcement) provides accessors on a number of stdlib types that will allow you to start using them. In particular, UnsafeBufferPointer (unsafely of course, but necessary for impedance matching), Array and InlineArray will be able to provide you with a usable Span.
Yes, but IIRC that would limit any homegrown Span interface over an imported C type to a with{Mutable}Span method, as there's no way to guarantee a stable address.
Ideally we could migrate the importer from using tuples to this new InlineArray type, however that would be massively source breaking.
Would it really though?
As long as it still supported the withUnsafeBytes(of:) and similar APIs, I'd be willing to wager that that would cover most use cases; I can't imagine there is that much code that uses tuples of 255 Int8s in a row without converting them to something more manageable first. It's just too unwieldy to work with in practice.
I agree. If I actually did have a 2048-element tuple that I was actually trying to work with and the compiler error told me I had to change it, my emotion on discovering this would likely be relief.
Will there be a protocol that aligns with the general use of such indexed collections? It seems really bad that an explicit type name with special behaviors and limitations doesn't have a protocol name that would allow one to change the implementation details of the storage without having to change code everywhere to deal with such a change in the application's storage needs.
I thought the same... It's possible but extremely unlikely someone would actually write name.123 to reference 123th byte of a tuple made out of 256 bytes. The amount of breaking existing code seems to be minimal.
I would also like to voice that I think this naming choice is particularly poor.
I recently open sourced the example code for "harmony", an embedded swift real-time audio project.
In this project, I have exactly 0 cases for Vector and specifically need an InlineArray<let N, T> to represent an AudioBuffer containing up to N stereo samples and need an InlineDeque<let K, S> to represent a Ring/FIFO of AudioBuffers containing up to K buffered elements.
I was trying to explain this to multiple individuals intimately familiar with Swift just this morning and we all found it extremely hard to follow, because currently InlineArray doesn't mean what everyone naturally expected it to. I really really hope theres an opportunity to revisit this name; the Inline prefixed names should be reserved for the types I mention above and not a Vector/Slab/FixedSizedArray type.
As the originator of the InlineArray name, I am a little biased, but it seems like the purpose of this post is to explicitly declare the end of the naming discussion.
I'm not suggesting Vector, I'm asking to avoid the Inline prefix because there is a family of types that map directly to InlineDeque, InlineSet, InlineArray, InlineDictionary that are all extremely valuable for embedded programming.
It's much more common to have fixed-capacity data structures than fixed-count data structures in embedded systems work. (Both are useful, but fixed-capacity just comes up more frequently.)
The type described in SE-0453 requires all elements to be valid. That is strictly not possible because the audio buffers are filled from data received over bluetooth. Depending on data tx rates, this may or may not be able to completely fill the audio buffer and in order to get gapless audio playback, the code needs to be able to handle partially filled buffers. quoting myself:
This type is exactly an Inline Array. It has inline storage, capacity, count, append and insert operations.
If these samples are in canonical format, the size is already known (N * 2 * MemoryLayout<Float>.stride). If the samples are in an arbitrary format, that seems like a perfect reason to write a wrapper InlineAudioBuffer<N, SampleType> type that uses InlineArray<N / MemoryLayout<SampleType>.stride, SampleType> as its internal storage.
I would also like to note InlineDeque/Ring/RingBuffer is the currency type for shuttling data around between independent processes/threads/execution contexts in embedded code.
As someone who has also written plenty of audio code in the past, having a partially-valid buffer is not at all an uncommon situation. You keep track of the valid subrange alongside your buffer, or you squelch to silence if the problem is amenable to it.