Skip to content

Conversation

@andrewmd5
Copy link

Adds an in-memory file system to the WASI bridge (with the ability to mount actual file descriptors.)

@andrewmd5
Copy link
Author

CI failure seems unrelated to these changes (out of storage space,) but if they are let me know.

func getPreopenPaths() -> [String]

/// Opens a directory and returns a WASIDir implementation.
func openDirectory(at path: String) throws -> any WASIDir
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if the use of existentials is justified here? Could we use opaque types instead?

Suggested change
func openDirectory(at path: String) throws -> any WASIDir
func openDirectory(at path: String) throws -> some WASIDir

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WASIDir seems to be defined as a protocol so I believe an existential is how its used elsewhere (i.e in Directory.swift)

import SystemPackage

/// Base protocol for all file system nodes in memory.
internal protocol MemFSNode: AnyObject {
Copy link
Member

@MaxDesiatov MaxDesiatov Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a strong reason to require AnyObject here? What would exactly classes (as opposed to non-copyable types) bring to the table other than reference counting performance hit?

Suggested change
internal protocol MemFSNode: AnyObject {
protocol MemFSNode {

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple file entries need to share mutable access to the same node (e.g., a file opened twice should see the same content). With classes, this is natural, both entries hold references to the same object. With non-copyable structs, we'd need an indirection layer (handles/indices into a central store), which adds complexity. Open to that refactor if the ref-counting overhead is measurable or if I am mistaken (Swift is arguably very new to me.)

///
/// This implementation provides access to actual files and directories on the host system,
/// with appropriate sandboxing through pre-opened directories.
public final class HostFileSystem: FileSystemProvider, FileSystem {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usual concern WRT classes overhead here. IIUC we're not relying on class hierarchies, so why not make this a non-copyable struct to avoid the ARC overhead?

Suggested change
public final class HostFileSystem: FileSystemProvider, FileSystem {
public struct HostFileSystem: FileSystemProvider, FileSystemImplementation, ~Copyable {

Copy link
Author

@andrewmd5 andrewmd5 Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I went with class here is that FileSystemImplementation needs to be stored as a property in WASIBridgeToHost, and Swift's existential types (any Protocol) don't support ~Copyable types. If we make this a non-copyable struct, we'd need to make WASIBridgeToHost generic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants