Foundation in Embedded Swift

Hi everyone,

I’d like to preface this post by providing some context. I’ve been working on some projects using Embedded Swift for the Playdate game console, including a series of libraries and frameworks to ease development (e.g., PlaydateUIKit, Renzo). In this process, I’ve more often than not found myself re-implementing some capabilities I’d find in the Foundation framework, such as date formatters.

In a discussion on the Playdate Squad Discord server, I had brought up a tangentially related topic and someone suggested to refactor some of my work to leverage the in-progress version of swift-foundation. However, I believe swift-foundation doesn’t support embedded environments. I would love to try leveraging what already exists, but I imagine embedded support would be a hard sell since there’s nothing stopping me from just making a version specifically tuned for the Playdate and calling it a day like I already am.

Which leads me to the point of this post: I’d like to investigate and hear from other fellow embedded developers. Would you want something like swift-foundation in your embedded workflows?

7 Likes

I’ve been toying around a bit with embedded swift, mainly on ESP32, and doing some Matter integrations.

while I can’t say I have felt the need for anything from Foundation yet, I can definitely understand that a need might arise once projects become more complex.

I understand that going down the path of making swift-foundation work on embedded might be harder than using your own foundational tools, I still think it might be worthwhile since it would e.g. enable us to build shared packages on top of it, which would work on all platforms where swift-foundation is available.

Just my two cents :grinning_face:

3 Likes

For sure! I’m hoping to hear more from other embedded folks to raise awareness and, eventually, file some sort of request on the swift-foundation repo for such support (maybe a couple PRs, if I’m feeling particularly adventurous).

Hi,

Good point. Maybe it makes sense to think about a lightweight “Foundation” for Embedded Swift — something that covers essentials like Date, Data, basic formatters, string helpers, JSON, fundamental enums, and small collection utilities.

At the same time, we need to remember that embedded systems have very limited resources. There is no room for large libraries or heavy runtimes, so this would have to be carefully scoped and balanced.

From my experience, one of the most frustrating parts of Embedded Swift is constantly having to reimplement common types and create workarounds just to write clean, idiomatic Swift code.

This is less about recreating Foundation as-is, and more about defining a common way of programming in Embedded Swift: shared names, shared concepts, and a small set of well-known types that mimic the most frequently used parts of Foundation, while staying fully portable and lightweight.

If you ever want to explore this idea further, feel free to reach out. I’d be happy to collaborate and help push this forward.

2 Likes

For sure, and that’s effectively what I’m currently doing at the moment on the Playdate side of things a la PDFoundation from PDKUtils. I’m not sure whether such a thing (lightweight Foundation) should be separate, but I imagine having some “core” version from the swift-foundation repo or making specific things available to embedded would be a nice step forward.

Thanks for the input!

1 Like

Hi @SoreGus do you have any specific types that you are looking for from Foundation in an embedded environment? Any specific types other than Data, Date, etc?

1 Like

Sure, something like following:

Data

An embedded-defined Data type should be the central byte container, similar to Data in regular Swift.

It is used to build and parse binary structures, move data between layers, and serve as the base for higher-level features like JSON and Base64.

Example: building a binary packet

var packet = Data()

packet.append(0xA1)                        // message type
packet.append(UInt16(48), endian: .little) // payload length
packet.append(contentsOf: "OK".utf8)
packet.append(0x0D)
packet.append(0x0A)

// out (hex): A1 30 00 4F 4B 0D 0A

Example: reading from a buffer

let type = packet.readUInt8(at: 0)
let length = packet.readUInt16(at: 1, endian: .little)
let text = packet.slice(from: 3, count: 2)

// out:
// type = 0xA1
// length = 48
// text = [0x4F, 0x4B]

String helpers

Text handling is common even in low-level code. A few well-chosen helpers remove a lot of boilerplate.

UTF-8 encoding

let message = "SWD OK ✅"
let bytes = Data(message.utf8)

// out (hex): 53 57 44 20 4F 4B 20 E2 9C 85

Base64

let raw = Data([0x01, 0x02, 0xFF])

let encoded = raw.base64EncodedString()
// out: "AQL/"

let decoded = Data(base64Encoded: encoded)
// out (hex): 01 02 FF

JSON Encoding and Decoding

JSON support can follow the same concepts and naming used in Swift (Encodable, Decodable, JSONEncoder, JSONDecoder), but implemented in a way that is explicit and deterministic.

Encoding example


struct Telemetry: Encodable {
    let temperature: Int
    let ok: Bool
}

let telemetry = Telemetry(temperature: 23, ok: true)

let encoder = JSONEncoder()

if let data = encoder.encode(telemetry) {
    // out: {"temperature":23,"ok":true}
    process(data)
} else {
    // encoding error
}

Decoding example

let input = data   // JSON bytes coming from somewhere

let decoder = JSONDecoder()

if let decoded = decoder.decode(Telemetry.self, from: input) {
    // decoded.temperature == 23
    // decoded.ok == true
} else {
    // decoding error
}

Timer

The core defines abstract types like Timer , but the actual time source often depends on hardware such as timers.

This means time support may vary across MCUs and architectures, which can reduce true multi-platform portability.

Timer represents a monotonic point in time and is mainly used to measure elapsed time.

let start = Timer.now()

// ... do work ...

let elapsed = Timer.now() - start

// out: elapsed = 12ms (example)

Date

Date represents an instant in time and does not depend on the MCU or RTC. It is a value type that typically stores a timestamp relative to a fixed epoch. The hardware dependency exists in how the current time is obtained. Date.now is a convenience API whose implementation may rely on RTC or some real world time source.

// Current instant
let now = Date.now

// Basic arithmetic
let inOneHour = now.addingTimeInterval(3600)

// String formatting (Swift-like)
let isoText = DateFormatter.iso8601.string(from: now)
// "2026-02-04T19:12:03Z"

let shortText = DateFormatter("yyyy-MM-dd").string(from: now)
// "2026-02-04"

// Parsing
let parsed = DateFormatter.iso8601.date(from: "2026-02-04T19:12:03Z")

// Comparison
if now > parsed {
    // ...
}

Because of this, while the Date type itself is portable, the behavior and accuracy of Date.now can vary across platforms and MCUs, depending on available hardware support.


Calendar

Calendar implementation.


URL and URLComponents

Lightweight URL parsing and construction using familiar Swift APIs.

var c = URLComponents()
c.scheme = "http"
c.host = "example.com"
c.port = 8080
c.path = "/api/status"
c.queryItems = [
    URLQueryItem(name: "id", value: "42"),
    URLQueryItem(name: "mode", value: "fast")
]

let url = URL(components: c)

// out: http://example.com:8080/api/status?id=42&mode=fast

What can be built on top of this core

With a clean Data type, JSON support, string helpers, collection utilities, and clear time abstractions, higher-level libraries become easier to build.

Examples include:

  • HTTP helpers
  • JSON-RPC layers
  • Structured logging
  • Binary framing and message schemas
  • Telemetry and sensor pipelines

All of these can be layered on top of the core, without coupling the core itself to hardware.


General Direction

The overall goal is a small, pure-Swift Foundation-like core, independent from hardware and architecture-specific details.

Some features — especially time and date — may require architecture- or MCU-specific implementations underneath. That risk is real and unavoidable, and it does reduce how “universal” those features can be.

By keeping hardware concerns outside the core and limiting the core to clear abstractions, Embedded Swift Foundation can remain mostly portable across MCUs, while still allowing more complete behavior when the hardware supports it.

This keeps the foundation stable, understandable, and reusable, even as different targets provide different capabilities underneath it.

2 Likes

Date is not tied to a clock. It can represent any point of time and is often used purely for calendar operations. Foundation doesn’t care where the time data comes from. Sure, it has a convenience factory method, now(), but that is hardly fundamental to the type.

I am not in the embedded space, but I would suggest considering a separation of concerns here, where Date is a fundamental type in EmbeddedFoundation, and there is a separate package that interfaces with available hardware time sources and extends Date with convenience methods akin to Date.now().

1 Like

You are 100% right! thank you.

Isn’t this just FoundationEssentials? I’m not sure on the status of Foundation for embedded but the whole point of essentials was to provide a lightweight subset of common types.

The issue with a calendar implementation is that this very quickly descends into needing ICU which ends up getting too big for embedded

4 Likes

I’d like to think that would be the case, but I’m not entirely sure. Nonetheless, that would be a great start!

That would be rather nice. The JSON APIs that currently exist in Playdate leave much to be desired, and it’s not particularly pleasant to work with. However, my understanding is that this is less of a Foundation issue and more of a "the embedded mode is missing the language features required to make this work”.

This was something I was recently discussing with Playdate folk because I want to have some sort of localization system in place that extends beyond the Playdate’s current supported localizations. At the time, I thought about leveraging the xcstrings format, but then I realized that we don’t have a great solution for JSON :sweat_smile:

1 Like

The one catch here is that the bare initializer Date() is the exact same as Date.now. That would mean that any call to the bare initializer would need to have access to some RTC clock which not all boards have (im not sure I've seen a actual chip with a builtin RTC, development boards or production boards sure... but not a chip).

Per the concept of calendars (which means locales and consequently ICU databases) this might overlap nicely with @Douglas_Gregor's pitch [Pitch] [Embedded] "Unicode" availability domain for APIs requiring the Unicode tables. Albeit a viral annotation to litter the Foundation codebase, but perhaps a good mechanism to indicate the "smallness"(or not) of impact of APIs.

Data would require an allocator of sorts, posix_memalign etc. JSON would require similar allocations but also probably would face some issues around existentials. URL might be more approachable than it has in the past with the recent work folks have been doing around that. URLSession however would likely be rather non-trivial.

Essentials is a good starting point to build for embedded, however I would guess that the other localization and networking sub projects of Foundation might be a bit of tall asks from my experience.

3 Likes

If I see calling FoundationEssentials "lightweight", especially in embedded, I can't help asking what footprint we're aiming at. Can Core + FoundationEssentials be in the kilos at some point?

What are the advantages of Data compared to [UInt8] ?

1 Like

If I see calling FoundationEssentials "lightweight", especially in embedded, I can't help asking what footprint we're aiming at. Can Core + FoundationEssentials be in the kilos at some point?

For the record, FoundationEssentials does have a Gregorian calendar implementation and does not depend on ICU. That’s what the vast majority of calendrical calculations will need.

3 Likes