Initial IronStorage project structure
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/target/
|
||||
/apple/IronStorage.xcodeproj/
|
||||
.DS_Store
|
||||
47
AGENTS.md
Normal file
47
AGENTS.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Repository instructions
|
||||
|
||||
## Architecture boundary
|
||||
|
||||
`crates/storage` owns all password-store behavior and all objects stored in or
|
||||
derived from a password-store repository. This includes filesystem layout,
|
||||
`.gpg-id` handling, GPG-compatible encryption and key handling, Git,
|
||||
synchronization, conflict handling, entry parsing, password generation, OTP,
|
||||
QR payloads, server/application identities, HTTPS Git credentials, and
|
||||
secure-secret-storage orchestration. Git remotes are HTTPS-only; reject other
|
||||
schemes before entering the Git transport.
|
||||
|
||||
The CLI, Ratatui, Iced, Swift, SwiftUI, AutoFill, and watchOS code may collect
|
||||
input, invoke the Rust API, and present Rust-provided state. They must not
|
||||
duplicate storage rules, derive domain state from display strings, or directly
|
||||
read or mutate a password-store repository.
|
||||
|
||||
Application code must not launch external processes. Do not invoke `pass`,
|
||||
`git`, `gpg`, shell commands, or helper executables. Use pure Rust libraries.
|
||||
Use FFI only where an operating-system API has no feasible Rust interface,
|
||||
such as Apple authentication and secure-storage APIs; keep domain decisions in
|
||||
`crates/storage`.
|
||||
|
||||
Keep project crates free of `unsafe` Rust. Isolate any unavoidable future FFI
|
||||
implementation in the smallest platform-specific module and document its
|
||||
safety contract.
|
||||
|
||||
## Compatibility
|
||||
|
||||
Compatibility means the upstream `pass` repository format and observable
|
||||
behavior, including `pass-otp`; IronStorage must not introduce a competing
|
||||
on-disk format. Prove new behavior with fixtures usable by both upstream tools
|
||||
and `crates/storage` without executing those tools at application runtime.
|
||||
|
||||
## Required checks
|
||||
|
||||
Run these from the repository root before committing:
|
||||
|
||||
```sh
|
||||
cargo fmt --all -- --check
|
||||
RUSTFLAGS="-D warnings" cargo check --workspace --all-targets
|
||||
cargo clippy --workspace --all-targets -- -D warnings
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
For Apple project changes, also run `xcodegen generate` from `apple/` and build
|
||||
the affected simulator targets.
|
||||
5516
Cargo.lock
generated
Normal file
5516
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
Cargo.toml
Normal file
22
Cargo.toml
Normal file
@@ -0,0 +1,22 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"apps/cli",
|
||||
"apps/desktop",
|
||||
"apps/tui",
|
||||
"crates/apple",
|
||||
"crates/storage",
|
||||
]
|
||||
resolver = "3"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
rust-version = "1.92"
|
||||
|
||||
[workspace.dependencies]
|
||||
clap = { version = "4.6", features = ["derive"] }
|
||||
crossterm = "0.29"
|
||||
iced = "0.14"
|
||||
ironstorage = { path = "crates/storage" }
|
||||
ratatui = { version = "0.30", default-features = false, features = ["crossterm_0_29", "layout-cache", "macros", "underline-color"] }
|
||||
uniffi = "0.32"
|
||||
59
DEPENDENCIES.md
Normal file
59
DEPENDENCIES.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Dependency and license review
|
||||
|
||||
Reviewed 2026-08-09. The project license remains intentionally unset until the
|
||||
GPG compatibility spike is complete.
|
||||
|
||||
## License direction
|
||||
|
||||
The preferred implementation stack permits IronStorage itself to use
|
||||
`MIT OR Apache-2.0`. That is the provisional choice, not yet a final license.
|
||||
|
||||
The current direct dependencies are:
|
||||
|
||||
| Crate | Purpose | License |
|
||||
| --- | --- | --- |
|
||||
| [clap 4.6](https://crates.io/crates/clap/4.6.4) | CLI parsing | MIT OR Apache-2.0 |
|
||||
| [crossterm 0.29](https://crates.io/crates/crossterm/0.29.0) | Terminal I/O | MIT |
|
||||
| [Ratatui 0.30](https://crates.io/crates/ratatui/0.30.2) | TUI | MIT |
|
||||
| [Iced 0.14](https://crates.io/crates/iced/0.14.0) | Desktop UI | MIT |
|
||||
| [UniFFI 0.32](https://crates.io/crates/uniffi/0.32.0) | Swift bridge | MPL-2.0 |
|
||||
|
||||
The activated transitive graph has no dependency that forces a GPL or LGPL
|
||||
license choice. UniFFI and its support crates are the only mandatory copyleft
|
||||
dependencies; MPL-2.0 is file-level copyleft and permits a larger work under a
|
||||
different license, subject to its notice and source-availability requirements.
|
||||
|
||||
`pass` is GPL-2.0-or-later and `pass-otp` is GPL-3.0. Treat their documentation
|
||||
and observable behavior as compatibility requirements, but do not copy their
|
||||
source or tests into IronStorage. Any such reuse requires a fresh license
|
||||
decision.
|
||||
|
||||
## Storage implementation candidates
|
||||
|
||||
| Slice | Candidate | License | Decision |
|
||||
| --- | --- | --- | --- |
|
||||
| GPG-compatible packets, encryption, and transferable keys | [`pgp` 0.20](https://crates.io/crates/pgp/0.20.0) | MIT OR Apache-2.0 | Preferred; pure Rust, including its default Rust bzip2 backend. Prove interoperability with GPG-produced fixtures first. |
|
||||
| Alternative GPG implementation | [`sequoia-openpgp` 2.4](https://crates.io/crates/sequoia-openpgp/2.4.1) | LGPL-2.0-or-later | Hold in reserve. Its default Nettle backend is native; its Rust backend exists, but the LGPL adds distribution work we can avoid. |
|
||||
| GnuPG integration | [`gpgme` 0.11](https://crates.io/crates/gpgme/0.11.0) | LGPL-2.1 | Reject: native GPGME/GnuPG integration and GPG engine processes violate the portability and no-process requirements. |
|
||||
| Local Git plus HTTPS fetch/push | [`gix` 0.86](https://crates.io/crates/gix/0.86.0) | MIT OR Apache-2.0 | Preferred with default features off and `blocking-http-transport-reqwest-rust-tls`; accept HTTPS remotes only and supply credentials directly. |
|
||||
| Git FFI fallback | [`git2` 0.21](https://crates.io/crates/git2/0.21.0) | MIT OR Apache-2.0 | Reject for now; it links libgit2 and is unnecessary for the HTTPS-only scope. |
|
||||
| Server/application credentials | [`keyring-core` 1.0](https://crates.io/crates/keyring-core/1.0.0), [`apple-native-keyring-store`](https://crates.io/crates/apple-native-keyring-store/1.0.2), [`windows-native-keyring-store`](https://crates.io/crates/windows-native-keyring-store/1.1.0), [`zbus-secret-service-keyring-store`](https://crates.io/crates/zbus-secret-service-keyring-store/1.0.0) | MIT OR Apache-2.0 | Preferred per-platform stores. The Apple protected store supports iOS/macOS protected data and biometric access. Use the Linux store's Rust crypto feature. |
|
||||
| Secret values in memory | [`secrecy` 0.10](https://crates.io/crates/secrecy/0.10.3), [`zeroize` 1.9](https://crates.io/crates/zeroize/1.9.0) | MIT OR Apache-2.0 | Preferred wrappers; still avoid unnecessary copies and logging. |
|
||||
| Password generation | [`rand`](https://crates.io/crates/rand) | MIT OR Apache-2.0 | Preferred using the operating-system CSPRNG. |
|
||||
| TOTP and HOTP | [`hmac`](https://crates.io/crates/hmac), [`sha1`](https://crates.io/crates/sha1), [`sha2`](https://crates.io/crates/sha2), [`data-encoding`](https://crates.io/crates/data-encoding), [`url`](https://crates.io/crates/url) | MIT or MIT OR Apache-2.0 | Preferred small implementation with RFC test vectors. `totp-rs` is MIT but rejects HOTP URIs, so it cannot cover all of `pass-otp`. |
|
||||
| QR output and desktop image input | [`qrcode` 0.14](https://crates.io/crates/qrcode/0.14.1), [`rqrr` 0.10](https://crates.io/crates/rqrr/0.10.1) | MIT OR Apache-2.0; second crate also includes ISC | Suitable. Apple camera scanning should use AVFoundation and pass only the decoded URI to Rust. |
|
||||
| Atomic file replacement | standard library, then [`tempfile`](https://crates.io/crates/tempfile) if needed | MIT OR Apache-2.0 | Start with the standard library; add `tempfile` only when the first safe-write implementation needs it. |
|
||||
|
||||
With this path, the central crate needs no third-party native GPG, Git, OTP, or
|
||||
QR library. Apple Security/LocalAuthentication, Windows Credential Manager,
|
||||
Linux Secret Service, and Apple camera APIs remain operating-system boundaries.
|
||||
|
||||
## Release gate
|
||||
|
||||
Before choosing and adding the project license:
|
||||
|
||||
1. Prove `pgp` can decrypt, encrypt, re-encrypt, and round-trip representative
|
||||
GPG files and exported keys from real `pass` stores.
|
||||
2. Lock the storage dependencies and run a full transitive license audit.
|
||||
3. Confirm the required notices/source offers for MPL-2.0 dependencies in every
|
||||
distributed app package.
|
||||
43
README.md
Normal file
43
README.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# IronStorage
|
||||
|
||||
IronStorage is a native client for
|
||||
[`pass`](https://git.zx2c4.com/password-store/about/) and
|
||||
[`pass-otp`](https://github.com/tadfisher/pass-otp).
|
||||
|
||||
`pass` stores entries as GPG-encrypted `.gpg` files in an ordinary directory
|
||||
tree (normally `~/.password-store`), selects one or more recipients through
|
||||
`.gpg-id` files, and can track changes in Git. IronStorage keeps that format
|
||||
and the first-party `pass` command behavior. `pass-otp` compatibility adds
|
||||
`otpauth://` secrets, OTP generation, and QR import/export.
|
||||
|
||||
The compatibility target includes init, list/show, find/grep, insert/edit,
|
||||
generate, remove, move/copy, and Git-backed commit and synchronization flows.
|
||||
Remote synchronization is HTTPS-only and uses server/application credentials
|
||||
kept in the operating system's secure store.
|
||||
|
||||
The central `ironstorage` Rust crate owns repository access, Git,
|
||||
GPG-compatible encryption and key handling, entries, OTP, synchronization,
|
||||
and platform-secure credential orchestration. Applications are presentation
|
||||
and interaction adapters only. Runtime subprocesses—including `pass`, `git`,
|
||||
and `gpg`—are forbidden; compatibility is implemented in Rust.
|
||||
|
||||
Candidate libraries and the pending project-license decision are tracked in
|
||||
[`DEPENDENCIES.md`](DEPENDENCIES.md).
|
||||
|
||||
## Project layout
|
||||
|
||||
```text
|
||||
crates/storage password-store domain and storage library
|
||||
crates/apple UniFFI boundary for Apple presentation code
|
||||
apps/cli pass-compatible command-line frontend
|
||||
apps/tui Ratatui frontend
|
||||
apps/desktop Iced desktop frontend for macOS, Windows, and Linux
|
||||
apple/ iPhone, AutoFill, and watchOS presentation targets
|
||||
```
|
||||
|
||||
The Apple project is generated with XcodeGen:
|
||||
|
||||
```sh
|
||||
cd apple
|
||||
xcodegen generate
|
||||
```
|
||||
31
apple/AutoFill-Info.plist
Normal file
31
apple/AutoFill-Info.plist
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>IronStorage AutoFill</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.authentication-services-credential-provider-ui</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).CredentialProviderViewController</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
553
apple/Generated/ironstorage_apple.swift
Normal file
553
apple/Generated/ironstorage_apple.swift
Normal file
@@ -0,0 +1,553 @@
|
||||
// This file was autogenerated by some hot garbage in the `uniffi` crate.
|
||||
// Trust me, you don't want to mess with it!
|
||||
|
||||
// swiftlint:disable all
|
||||
import Foundation
|
||||
|
||||
// Depending on the consumer's build setup, the low-level FFI code
|
||||
// might be in a separate module, or it might be compiled inline into
|
||||
// this module. This is a bit of light hackery to work with both.
|
||||
#if canImport(ironstorage_appleFFI)
|
||||
import ironstorage_appleFFI
|
||||
#endif
|
||||
|
||||
fileprivate extension RustBuffer {
|
||||
// Allocate a new buffer, copying the contents of a `UInt8` array.
|
||||
init(bytes: [UInt8]) {
|
||||
let rbuf = bytes.withUnsafeBufferPointer { ptr in
|
||||
RustBuffer.from(ptr)
|
||||
}
|
||||
self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data)
|
||||
}
|
||||
|
||||
static func empty() -> RustBuffer {
|
||||
RustBuffer(capacity: 0, len:0, data: nil)
|
||||
}
|
||||
|
||||
static func from(_ ptr: UnsafeBufferPointer<UInt8>) -> RustBuffer {
|
||||
try! rustCall { ffi_ironstorage_apple_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) }
|
||||
}
|
||||
|
||||
// Frees the buffer in place.
|
||||
// The buffer must not be used after this is called.
|
||||
func deallocate() {
|
||||
try! rustCall { ffi_ironstorage_apple_rustbuffer_free(self, $0) }
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension ForeignBytes {
|
||||
init(bufferPointer: UnsafeBufferPointer<UInt8>) {
|
||||
self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress)
|
||||
}
|
||||
|
||||
init(rawBufferPointer: UnsafeRawBufferPointer) {
|
||||
self.init(
|
||||
len: Int32(rawBufferPointer.count),
|
||||
data: rawBufferPointer.baseAddress?.assumingMemoryBound(to: UInt8.self)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Converter for `&[u8]` / `[ByRef] bytes` arguments.
|
||||
//
|
||||
// Conforms to `FfiConverter` so the compiler enforces the full converter
|
||||
// method set. Only the scope-bound `lower(_:_body:)` overload is sound —
|
||||
// zero-copy byte buffers only flow foreign -> Rust, and only in argument
|
||||
// position. The four protocol-witness methods (`lift`, `lower`, `read`,
|
||||
// `write`) `fatalError` at runtime if anyone reaches them.
|
||||
//
|
||||
// The scope-bound `lower` takes a closure because the `ForeignBytes`
|
||||
// pointer is only guaranteed valid for the duration of
|
||||
// `Data.withUnsafeBytes`. Callers must run the full FFI call inside
|
||||
// the closure body.
|
||||
fileprivate enum FfiConverterByRefBytes: FfiConverter {
|
||||
typealias SwiftType = Data
|
||||
typealias FfiType = ForeignBytes
|
||||
|
||||
static func lower<R>(_ value: Data, _ body: (ForeignBytes) throws -> R) rethrows -> R {
|
||||
return try value.withUnsafeBytes { rawBuf in
|
||||
try body(ForeignBytes(rawBufferPointer: rawBuf))
|
||||
}
|
||||
}
|
||||
|
||||
static func lower(_ value: Data) -> ForeignBytes {
|
||||
fatalError("ByRef bytes cannot use the plain lower: returning ForeignBytes escapes the Data.withUnsafeBytes scope. Use the scope-bound lower(_:_body:) overload instead.")
|
||||
}
|
||||
|
||||
static func lift(_ value: ForeignBytes) throws -> Data {
|
||||
fatalError("ByRef bytes cannot be lifted: zero-copy &[u8] only flows foreign->Rust")
|
||||
}
|
||||
|
||||
static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Data {
|
||||
fatalError("ByRef bytes cannot be read from a buffer: zero-copy &[u8] is only supported in argument position, not nested in records/options/etc.")
|
||||
}
|
||||
|
||||
static func write(_ value: Data, into buf: inout [UInt8]) {
|
||||
fatalError("ByRef bytes cannot be written to a buffer: zero-copy &[u8] is only supported in argument position, not nested in records/options/etc.")
|
||||
}
|
||||
}
|
||||
|
||||
// For every type used in the interface, we provide helper methods for conveniently
|
||||
// lifting and lowering that type from C-compatible data, and for reading and writing
|
||||
// values of that type in a buffer.
|
||||
|
||||
// Helper classes/extensions that don't change.
|
||||
// Someday, this will be in a library of its own.
|
||||
|
||||
fileprivate extension Data {
|
||||
init(rustBuffer: RustBuffer) {
|
||||
self.init(
|
||||
bytesNoCopy: rustBuffer.data!,
|
||||
count: Int(rustBuffer.len),
|
||||
deallocator: .none
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Define reader functionality. Normally this would be defined in a class or
|
||||
// struct, but we use standalone functions instead in order to make external
|
||||
// types work.
|
||||
//
|
||||
// With external types, one swift source file needs to be able to call the read
|
||||
// method on another source file's FfiConverter, but then what visibility
|
||||
// should Reader have?
|
||||
// - If Reader is fileprivate, then this means the read() must also
|
||||
// be fileprivate, which doesn't work with external types.
|
||||
// - If Reader is internal/public, we'll get compile errors since both source
|
||||
// files will try define the same type.
|
||||
//
|
||||
// Instead, the read() method and these helper functions input a tuple of data
|
||||
|
||||
fileprivate func createReader(data: Data) -> (data: Data, offset: Data.Index) {
|
||||
(data: data, offset: 0)
|
||||
}
|
||||
|
||||
// Reads an integer at the current offset, in big-endian order, and advances
|
||||
// the offset on success. Throws if reading the integer would move the
|
||||
// offset past the end of the buffer.
|
||||
fileprivate func readInt<T: FixedWidthInteger>(_ reader: inout (data: Data, offset: Data.Index)) throws -> T {
|
||||
let range = reader.offset..<reader.offset + MemoryLayout<T>.size
|
||||
guard reader.data.count >= range.upperBound else {
|
||||
throw UniffiInternalError.bufferOverflow
|
||||
}
|
||||
if T.self == UInt8.self {
|
||||
let value = reader.data[reader.offset]
|
||||
reader.offset += 1
|
||||
return value as! T
|
||||
}
|
||||
var value: T = 0
|
||||
let _ = withUnsafeMutableBytes(of: &value, { reader.data.copyBytes(to: $0, from: range)})
|
||||
reader.offset = range.upperBound
|
||||
return value.bigEndian
|
||||
}
|
||||
|
||||
// Reads an arbitrary number of bytes, to be used to read
|
||||
// raw bytes, this is useful when lifting strings
|
||||
fileprivate func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> Array<UInt8> {
|
||||
let range = reader.offset..<(reader.offset+count)
|
||||
guard reader.data.count >= range.upperBound else {
|
||||
throw UniffiInternalError.bufferOverflow
|
||||
}
|
||||
var value = [UInt8](repeating: 0, count: count)
|
||||
value.withUnsafeMutableBufferPointer({ buffer in
|
||||
reader.data.copyBytes(to: buffer, from: range)
|
||||
})
|
||||
reader.offset = range.upperBound
|
||||
return value
|
||||
}
|
||||
|
||||
// Reads a float at the current offset.
|
||||
fileprivate func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float {
|
||||
return Float(bitPattern: try readInt(&reader))
|
||||
}
|
||||
|
||||
// Reads a float at the current offset.
|
||||
fileprivate func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double {
|
||||
return Double(bitPattern: try readInt(&reader))
|
||||
}
|
||||
|
||||
// Indicates if the offset has reached the end of the buffer.
|
||||
fileprivate func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool {
|
||||
return reader.offset < reader.data.count
|
||||
}
|
||||
|
||||
// Define writer functionality. Normally this would be defined in a class or
|
||||
// struct, but we use standalone functions instead in order to make external
|
||||
// types work. See the above discussion on Readers for details.
|
||||
|
||||
fileprivate func createWriter() -> [UInt8] {
|
||||
return []
|
||||
}
|
||||
|
||||
fileprivate func writeBytes<S>(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 {
|
||||
writer.append(contentsOf: byteArr)
|
||||
}
|
||||
|
||||
// Writes an integer in big-endian order.
|
||||
//
|
||||
// Warning: make sure what you are trying to write
|
||||
// is in the correct type!
|
||||
fileprivate func writeInt<T: FixedWidthInteger>(_ writer: inout [UInt8], _ value: T) {
|
||||
var value = value.bigEndian
|
||||
withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) }
|
||||
}
|
||||
|
||||
fileprivate func writeFloat(_ writer: inout [UInt8], _ value: Float) {
|
||||
writeInt(&writer, value.bitPattern)
|
||||
}
|
||||
|
||||
fileprivate func writeDouble(_ writer: inout [UInt8], _ value: Double) {
|
||||
writeInt(&writer, value.bitPattern)
|
||||
}
|
||||
|
||||
// Protocol for types that transfer other types across the FFI. This is
|
||||
// analogous to the Rust trait of the same name.
|
||||
fileprivate protocol FfiConverter {
|
||||
associatedtype FfiType
|
||||
associatedtype SwiftType
|
||||
|
||||
static func lift(_ value: FfiType) throws -> SwiftType
|
||||
static func lower(_ value: SwiftType) -> FfiType
|
||||
static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType
|
||||
static func write(_ value: SwiftType, into buf: inout [UInt8])
|
||||
}
|
||||
|
||||
// Types conforming to `Primitive` pass themselves directly over the FFI.
|
||||
fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { }
|
||||
|
||||
extension FfiConverterPrimitive {
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public static func lift(_ value: FfiType) throws -> SwiftType {
|
||||
return value
|
||||
}
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public static func lower(_ value: SwiftType) -> FfiType {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`.
|
||||
// Used for complex types where it's hard to write a custom lift/lower.
|
||||
fileprivate protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {}
|
||||
|
||||
extension FfiConverterRustBuffer {
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public static func lift(_ buf: RustBuffer) throws -> SwiftType {
|
||||
var reader = createReader(data: Data(rustBuffer: buf))
|
||||
let value = try read(from: &reader)
|
||||
if hasRemaining(reader) {
|
||||
throw UniffiInternalError.incompleteData
|
||||
}
|
||||
buf.deallocate()
|
||||
return value
|
||||
}
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
public static func lower(_ value: SwiftType) -> RustBuffer {
|
||||
var writer = createWriter()
|
||||
write(value, into: &writer)
|
||||
return RustBuffer(bytes: writer)
|
||||
}
|
||||
}
|
||||
// An error type for FFI errors. These errors occur at the UniFFI level, not
|
||||
// the library level.
|
||||
fileprivate enum UniffiInternalError: LocalizedError {
|
||||
case bufferOverflow
|
||||
case incompleteData
|
||||
case unexpectedOptionalTag
|
||||
case unexpectedEnumCase
|
||||
case unexpectedNullPointer
|
||||
case unexpectedRustCallStatusCode
|
||||
case unexpectedRustCallError
|
||||
case unexpectedStaleHandle
|
||||
case rustPanic(_ message: String)
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .bufferOverflow: return "Reading the requested value would read past the end of the buffer"
|
||||
case .incompleteData: return "The buffer still has data after lifting its containing value"
|
||||
case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1"
|
||||
case .unexpectedEnumCase: return "Raw enum value doesn't match any cases"
|
||||
case .unexpectedNullPointer: return "Raw pointer value was null"
|
||||
case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code"
|
||||
case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified"
|
||||
case .unexpectedStaleHandle: return "The object in the handle map has been dropped already"
|
||||
case let .rustPanic(message): return message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension NSLock {
|
||||
func withLock<T>(f: () throws -> T) rethrows -> T {
|
||||
self.lock()
|
||||
defer { self.unlock() }
|
||||
return try f()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate let CALL_SUCCESS: Int8 = 0
|
||||
fileprivate let CALL_ERROR: Int8 = 1
|
||||
fileprivate let CALL_UNEXPECTED_ERROR: Int8 = 2
|
||||
fileprivate let CALL_CANCELLED: Int8 = 3
|
||||
|
||||
fileprivate extension RustCallStatus {
|
||||
init() {
|
||||
self.init(
|
||||
code: CALL_SUCCESS,
|
||||
errorBuf: RustBuffer.init(
|
||||
capacity: 0,
|
||||
len: 0,
|
||||
data: nil
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func rustCall<T>(_ callback: (UnsafeMutablePointer<RustCallStatus>) -> T) throws -> T {
|
||||
let neverThrow: ((RustBuffer) throws -> Never)? = nil
|
||||
return try makeRustCall(callback, errorHandler: neverThrow)
|
||||
}
|
||||
|
||||
private func rustCallWithError<T, E: Swift.Error>(
|
||||
_ errorHandler: @escaping (RustBuffer) throws -> E,
|
||||
_ callback: (UnsafeMutablePointer<RustCallStatus>) -> T) throws -> T {
|
||||
try makeRustCall(callback, errorHandler: errorHandler)
|
||||
}
|
||||
|
||||
private func makeRustCall<T, E: Swift.Error>(
|
||||
_ callback: (UnsafeMutablePointer<RustCallStatus>) -> T,
|
||||
errorHandler: ((RustBuffer) throws -> E)?
|
||||
) throws -> T {
|
||||
uniffiEnsureIronstorageAppleInitialized()
|
||||
var callStatus = RustCallStatus.init()
|
||||
let returnedVal = callback(&callStatus)
|
||||
try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler)
|
||||
return returnedVal
|
||||
}
|
||||
|
||||
private func uniffiCheckCallStatus<E: Swift.Error>(
|
||||
callStatus: RustCallStatus,
|
||||
errorHandler: ((RustBuffer) throws -> E)?
|
||||
) throws {
|
||||
switch callStatus.code {
|
||||
case CALL_SUCCESS:
|
||||
return
|
||||
|
||||
case CALL_ERROR:
|
||||
if let errorHandler = errorHandler {
|
||||
throw try errorHandler(callStatus.errorBuf)
|
||||
} else {
|
||||
callStatus.errorBuf.deallocate()
|
||||
throw UniffiInternalError.unexpectedRustCallError
|
||||
}
|
||||
|
||||
case CALL_UNEXPECTED_ERROR:
|
||||
// When the rust code sees a panic, it tries to construct a RustBuffer
|
||||
// with the message. But if that code panics, then it just sends back
|
||||
// an empty buffer.
|
||||
if callStatus.errorBuf.len > 0 {
|
||||
throw UniffiInternalError.rustPanic(try FfiConverterString.lift(callStatus.errorBuf))
|
||||
} else {
|
||||
callStatus.errorBuf.deallocate()
|
||||
throw UniffiInternalError.rustPanic("Rust panic")
|
||||
}
|
||||
|
||||
case CALL_CANCELLED:
|
||||
fatalError("Cancellation not supported yet")
|
||||
|
||||
default:
|
||||
throw UniffiInternalError.unexpectedRustCallStatusCode
|
||||
}
|
||||
}
|
||||
|
||||
private func uniffiTraitInterfaceCall<T>(
|
||||
callStatus: UnsafeMutablePointer<RustCallStatus>,
|
||||
makeCall: () throws -> T,
|
||||
writeReturn: (T) -> ()
|
||||
) {
|
||||
do {
|
||||
try writeReturn(makeCall())
|
||||
} catch let error {
|
||||
callStatus.pointee.code = CALL_UNEXPECTED_ERROR
|
||||
callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error))
|
||||
}
|
||||
}
|
||||
|
||||
private func uniffiTraitInterfaceCallWithError<T, E>(
|
||||
callStatus: UnsafeMutablePointer<RustCallStatus>,
|
||||
makeCall: () throws -> T,
|
||||
writeReturn: (T) -> (),
|
||||
lowerError: (E) -> RustBuffer
|
||||
) {
|
||||
do {
|
||||
try writeReturn(makeCall())
|
||||
} catch let error as E {
|
||||
callStatus.pointee.code = CALL_ERROR
|
||||
callStatus.pointee.errorBuf = lowerError(error)
|
||||
} catch {
|
||||
callStatus.pointee.code = CALL_UNEXPECTED_ERROR
|
||||
callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error))
|
||||
}
|
||||
}
|
||||
// Initial value and increment amount for handles.
|
||||
// These ensure that SWIFT handles always have the lowest bit set
|
||||
fileprivate let UNIFFI_HANDLEMAP_INITIAL: UInt64 = 1
|
||||
fileprivate let UNIFFI_HANDLEMAP_DELTA: UInt64 = 2
|
||||
|
||||
fileprivate final class UniffiHandleMap<T>: @unchecked Sendable {
|
||||
// All mutation happens with this lock held, which is why we implement @unchecked Sendable.
|
||||
private let lock = NSLock()
|
||||
private var map: [UInt64: T] = [:]
|
||||
private var currentHandle: UInt64 = UNIFFI_HANDLEMAP_INITIAL
|
||||
|
||||
func insert(obj: T) -> UInt64 {
|
||||
lock.withLock {
|
||||
return doInsert(obj)
|
||||
}
|
||||
}
|
||||
|
||||
// Low-level insert function, this assumes `lock` is held.
|
||||
private func doInsert(_ obj: T) -> UInt64 {
|
||||
let handle = currentHandle
|
||||
currentHandle += UNIFFI_HANDLEMAP_DELTA
|
||||
map[handle] = obj
|
||||
return handle
|
||||
}
|
||||
|
||||
func get(handle: UInt64) throws -> T {
|
||||
try lock.withLock {
|
||||
guard let obj = map[handle] else {
|
||||
throw UniffiInternalError.unexpectedStaleHandle
|
||||
}
|
||||
return obj
|
||||
}
|
||||
}
|
||||
|
||||
func clone(handle: UInt64) throws -> UInt64 {
|
||||
try lock.withLock {
|
||||
guard let obj = map[handle] else {
|
||||
throw UniffiInternalError.unexpectedStaleHandle
|
||||
}
|
||||
return doInsert(obj)
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func remove(handle: UInt64) throws -> T {
|
||||
try lock.withLock {
|
||||
guard let obj = map.removeValue(forKey: handle) else {
|
||||
throw UniffiInternalError.unexpectedStaleHandle
|
||||
}
|
||||
return obj
|
||||
}
|
||||
}
|
||||
|
||||
var count: Int {
|
||||
get {
|
||||
map.count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Public interface members begin here.
|
||||
|
||||
|
||||
#if swift(>=5.8)
|
||||
@_documentation(visibility: private)
|
||||
#endif
|
||||
fileprivate struct FfiConverterString: FfiConverter {
|
||||
typealias SwiftType = String
|
||||
typealias FfiType = RustBuffer
|
||||
|
||||
public static func lift(_ value: RustBuffer) throws -> String {
|
||||
defer {
|
||||
value.deallocate()
|
||||
}
|
||||
if value.data == nil {
|
||||
return String()
|
||||
}
|
||||
let bytes = UnsafeBufferPointer<UInt8>(start: value.data!, count: Int(value.len))
|
||||
// Use Swift's native UTF-8 decoder; `String(bytes:encoding:.utf8)` goes
|
||||
// through Foundation's NSString and silently strips a leading U+FEFF BOM.
|
||||
// Invalid UTF-8 substitutes U+FFFD instead of trapping (unreachable
|
||||
// given Rust's `String` invariant).
|
||||
return String(decoding: bytes, as: UTF8.self)
|
||||
}
|
||||
|
||||
public static func lower(_ value: String) -> RustBuffer {
|
||||
return value.utf8CString.withUnsafeBufferPointer { ptr in
|
||||
// The swift string gives us int8_t, we want uint8_t.
|
||||
ptr.withMemoryRebound(to: UInt8.self) { ptr in
|
||||
// The swift string gives us a trailing null byte, we don't want it.
|
||||
let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1))
|
||||
return RustBuffer.from(buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String {
|
||||
let len: Int32 = try readInt(&buf)
|
||||
// See `lift` above for why we avoid Foundation's NSString-backed decoder here.
|
||||
return String(decoding: try readBytes(&buf, count: Int(len)), as: UTF8.self)
|
||||
}
|
||||
|
||||
public static func write(_ value: String, into buf: inout [UInt8]) {
|
||||
let len = Int32(value.utf8.count)
|
||||
writeInt(&buf, len)
|
||||
writeBytes(&buf, value.utf8)
|
||||
}
|
||||
}
|
||||
public func productName() -> String {
|
||||
return try! FfiConverterString.lift(try! rustCall() {
|
||||
uniffiCallStatus in
|
||||
uniffi_ironstorage_apple_fn_func_product_name(uniffiCallStatus
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
private enum InitializationResult {
|
||||
case ok
|
||||
case contractVersionMismatch
|
||||
case apiChecksumMismatch
|
||||
}
|
||||
// Use a global variable to perform the versioning checks. Swift ensures that
|
||||
// the code inside is only computed once.
|
||||
private let initializationResult: InitializationResult = {
|
||||
// Get the bindings contract version from our ComponentInterface
|
||||
let bindings_contract_version = 30
|
||||
// Get the scaffolding contract version by calling the into the dylib
|
||||
let scaffolding_contract_version = ffi_ironstorage_apple_uniffi_contract_version()
|
||||
if bindings_contract_version != scaffolding_contract_version {
|
||||
return InitializationResult.contractVersionMismatch
|
||||
}
|
||||
if (uniffi_ironstorage_apple_checksum_func_product_name() != 43533) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
|
||||
return InitializationResult.ok
|
||||
}()
|
||||
|
||||
// Make the ensure init function public so that other modules which have external type references to
|
||||
// our types can call it.
|
||||
public func uniffiEnsureIronstorageAppleInitialized() {
|
||||
switch initializationResult {
|
||||
case .ok:
|
||||
break
|
||||
case .contractVersionMismatch:
|
||||
fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project")
|
||||
case .apiChecksumMismatch:
|
||||
fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:enable all
|
||||
523
apple/Generated/ironstorage_appleFFI.h
Normal file
523
apple/Generated/ironstorage_appleFFI.h
Normal file
@@ -0,0 +1,523 @@
|
||||
// This file was autogenerated by some hot garbage in the `uniffi` crate.
|
||||
// Trust me, you don't want to mess with it!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// The following structs are used to implement the lowest level
|
||||
// of the FFI, and thus useful to multiple uniffied crates.
|
||||
// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H.
|
||||
#ifdef UNIFFI_SHARED_H
|
||||
// We also try to prevent mixing versions of shared uniffi header structs.
|
||||
// If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4
|
||||
#ifndef UNIFFI_SHARED_HEADER_V4
|
||||
#error Combining helper code from multiple versions of uniffi is not supported
|
||||
#endif // ndef UNIFFI_SHARED_HEADER_V4
|
||||
#else
|
||||
#define UNIFFI_SHARED_H
|
||||
#define UNIFFI_SHARED_HEADER_V4
|
||||
// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️
|
||||
// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️
|
||||
|
||||
typedef struct RustBuffer
|
||||
{
|
||||
uint64_t capacity;
|
||||
uint64_t len;
|
||||
uint8_t *_Nullable data;
|
||||
} RustBuffer;
|
||||
|
||||
typedef struct ForeignBytes
|
||||
{
|
||||
int32_t len;
|
||||
const uint8_t *_Nullable data;
|
||||
} ForeignBytes;
|
||||
|
||||
// Error definitions
|
||||
typedef struct RustCallStatus {
|
||||
int8_t code;
|
||||
RustBuffer errorBuf;
|
||||
} RustCallStatus;
|
||||
|
||||
// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️
|
||||
// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️
|
||||
#endif // def UNIFFI_SHARED_H
|
||||
#ifndef UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK
|
||||
#define UNIFFI_FFIDEF_RUST_FUTURE_CONTINUATION_CALLBACK
|
||||
typedef void (*UniffiRustFutureContinuationCallback)(uint64_t, int8_t
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK
|
||||
typedef void (*UniffiForeignFutureDroppedCallback)(uint64_t
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE
|
||||
#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_FREE
|
||||
typedef void (*UniffiCallbackInterfaceFree)(uint64_t
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE
|
||||
#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_CLONE
|
||||
typedef uint64_t (*UniffiCallbackInterfaceClone)(uint64_t
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_DROPPED_CALLBACK_STRUCT
|
||||
typedef struct UniffiForeignFutureDroppedCallbackStruct {
|
||||
uint64_t handle;
|
||||
UniffiForeignFutureDroppedCallback _Nonnull free;
|
||||
} UniffiForeignFutureDroppedCallbackStruct;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U8
|
||||
typedef struct UniffiForeignFutureResultU8 {
|
||||
uint8_t returnValue;
|
||||
RustCallStatus callStatus;
|
||||
} UniffiForeignFutureResultU8;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U8
|
||||
typedef void (*UniffiForeignFutureCompleteU8)(uint64_t, UniffiForeignFutureResultU8
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I8
|
||||
typedef struct UniffiForeignFutureResultI8 {
|
||||
int8_t returnValue;
|
||||
RustCallStatus callStatus;
|
||||
} UniffiForeignFutureResultI8;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I8
|
||||
typedef void (*UniffiForeignFutureCompleteI8)(uint64_t, UniffiForeignFutureResultI8
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U16
|
||||
typedef struct UniffiForeignFutureResultU16 {
|
||||
uint16_t returnValue;
|
||||
RustCallStatus callStatus;
|
||||
} UniffiForeignFutureResultU16;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U16
|
||||
typedef void (*UniffiForeignFutureCompleteU16)(uint64_t, UniffiForeignFutureResultU16
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I16
|
||||
typedef struct UniffiForeignFutureResultI16 {
|
||||
int16_t returnValue;
|
||||
RustCallStatus callStatus;
|
||||
} UniffiForeignFutureResultI16;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I16
|
||||
typedef void (*UniffiForeignFutureCompleteI16)(uint64_t, UniffiForeignFutureResultI16
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U32
|
||||
typedef struct UniffiForeignFutureResultU32 {
|
||||
uint32_t returnValue;
|
||||
RustCallStatus callStatus;
|
||||
} UniffiForeignFutureResultU32;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U32
|
||||
typedef void (*UniffiForeignFutureCompleteU32)(uint64_t, UniffiForeignFutureResultU32
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I32
|
||||
typedef struct UniffiForeignFutureResultI32 {
|
||||
int32_t returnValue;
|
||||
RustCallStatus callStatus;
|
||||
} UniffiForeignFutureResultI32;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I32
|
||||
typedef void (*UniffiForeignFutureCompleteI32)(uint64_t, UniffiForeignFutureResultI32
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_U64
|
||||
typedef struct UniffiForeignFutureResultU64 {
|
||||
uint64_t returnValue;
|
||||
RustCallStatus callStatus;
|
||||
} UniffiForeignFutureResultU64;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_U64
|
||||
typedef void (*UniffiForeignFutureCompleteU64)(uint64_t, UniffiForeignFutureResultU64
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_I64
|
||||
typedef struct UniffiForeignFutureResultI64 {
|
||||
int64_t returnValue;
|
||||
RustCallStatus callStatus;
|
||||
} UniffiForeignFutureResultI64;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_I64
|
||||
typedef void (*UniffiForeignFutureCompleteI64)(uint64_t, UniffiForeignFutureResultI64
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F32
|
||||
typedef struct UniffiForeignFutureResultF32 {
|
||||
float returnValue;
|
||||
RustCallStatus callStatus;
|
||||
} UniffiForeignFutureResultF32;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F32
|
||||
typedef void (*UniffiForeignFutureCompleteF32)(uint64_t, UniffiForeignFutureResultF32
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_F64
|
||||
typedef struct UniffiForeignFutureResultF64 {
|
||||
double returnValue;
|
||||
RustCallStatus callStatus;
|
||||
} UniffiForeignFutureResultF64;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_F64
|
||||
typedef void (*UniffiForeignFutureCompleteF64)(uint64_t, UniffiForeignFutureResultF64
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_RUST_BUFFER
|
||||
typedef struct UniffiForeignFutureResultRustBuffer {
|
||||
RustBuffer returnValue;
|
||||
RustCallStatus callStatus;
|
||||
} UniffiForeignFutureResultRustBuffer;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER
|
||||
typedef void (*UniffiForeignFutureCompleteRustBuffer)(uint64_t, UniffiForeignFutureResultRustBuffer
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_RESULT_VOID
|
||||
typedef struct UniffiForeignFutureResultVoid {
|
||||
RustCallStatus callStatus;
|
||||
} UniffiForeignFutureResultVoid;
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID
|
||||
#define UNIFFI_FFIDEF_FOREIGN_FUTURE_COMPLETE_VOID
|
||||
typedef void (*UniffiForeignFutureCompleteVoid)(uint64_t, UniffiForeignFutureResultVoid
|
||||
);
|
||||
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_FUNC_PRODUCT_NAME
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_FN_FUNC_PRODUCT_NAME
|
||||
RustBuffer uniffi_ironstorage_apple_fn_func_product_name(RustCallStatus *_Nonnull out_status
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUSTBUFFER_ALLOC
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUSTBUFFER_ALLOC
|
||||
RustBuffer ffi_ironstorage_apple_rustbuffer_alloc(uint64_t size, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUSTBUFFER_FROM_BYTES
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUSTBUFFER_FROM_BYTES
|
||||
RustBuffer ffi_ironstorage_apple_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUSTBUFFER_FREE
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUSTBUFFER_FREE
|
||||
void ffi_ironstorage_apple_rustbuffer_free(RustBuffer buf, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUSTBUFFER_RESERVE
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUSTBUFFER_RESERVE
|
||||
RustBuffer ffi_ironstorage_apple_rustbuffer_reserve(RustBuffer buf, uint64_t additional, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_U8
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_U8
|
||||
void ffi_ironstorage_apple_rust_future_poll_u8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_U8
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_U8
|
||||
void ffi_ironstorage_apple_rust_future_cancel_u8(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_U8
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_U8
|
||||
void ffi_ironstorage_apple_rust_future_free_u8(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_U8
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_U8
|
||||
uint8_t ffi_ironstorage_apple_rust_future_complete_u8(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_I8
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_I8
|
||||
void ffi_ironstorage_apple_rust_future_poll_i8(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_I8
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_I8
|
||||
void ffi_ironstorage_apple_rust_future_cancel_i8(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_I8
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_I8
|
||||
void ffi_ironstorage_apple_rust_future_free_i8(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_I8
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_I8
|
||||
int8_t ffi_ironstorage_apple_rust_future_complete_i8(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_U16
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_U16
|
||||
void ffi_ironstorage_apple_rust_future_poll_u16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_U16
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_U16
|
||||
void ffi_ironstorage_apple_rust_future_cancel_u16(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_U16
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_U16
|
||||
void ffi_ironstorage_apple_rust_future_free_u16(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_U16
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_U16
|
||||
uint16_t ffi_ironstorage_apple_rust_future_complete_u16(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_I16
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_I16
|
||||
void ffi_ironstorage_apple_rust_future_poll_i16(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_I16
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_I16
|
||||
void ffi_ironstorage_apple_rust_future_cancel_i16(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_I16
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_I16
|
||||
void ffi_ironstorage_apple_rust_future_free_i16(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_I16
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_I16
|
||||
int16_t ffi_ironstorage_apple_rust_future_complete_i16(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_U32
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_U32
|
||||
void ffi_ironstorage_apple_rust_future_poll_u32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_U32
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_U32
|
||||
void ffi_ironstorage_apple_rust_future_cancel_u32(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_U32
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_U32
|
||||
void ffi_ironstorage_apple_rust_future_free_u32(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_U32
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_U32
|
||||
uint32_t ffi_ironstorage_apple_rust_future_complete_u32(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_I32
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_I32
|
||||
void ffi_ironstorage_apple_rust_future_poll_i32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_I32
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_I32
|
||||
void ffi_ironstorage_apple_rust_future_cancel_i32(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_I32
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_I32
|
||||
void ffi_ironstorage_apple_rust_future_free_i32(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_I32
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_I32
|
||||
int32_t ffi_ironstorage_apple_rust_future_complete_i32(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_U64
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_U64
|
||||
void ffi_ironstorage_apple_rust_future_poll_u64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_U64
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_U64
|
||||
void ffi_ironstorage_apple_rust_future_cancel_u64(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_U64
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_U64
|
||||
void ffi_ironstorage_apple_rust_future_free_u64(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_U64
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_U64
|
||||
uint64_t ffi_ironstorage_apple_rust_future_complete_u64(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_I64
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_I64
|
||||
void ffi_ironstorage_apple_rust_future_poll_i64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_I64
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_I64
|
||||
void ffi_ironstorage_apple_rust_future_cancel_i64(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_I64
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_I64
|
||||
void ffi_ironstorage_apple_rust_future_free_i64(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_I64
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_I64
|
||||
int64_t ffi_ironstorage_apple_rust_future_complete_i64(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_F32
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_F32
|
||||
void ffi_ironstorage_apple_rust_future_poll_f32(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_F32
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_F32
|
||||
void ffi_ironstorage_apple_rust_future_cancel_f32(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_F32
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_F32
|
||||
void ffi_ironstorage_apple_rust_future_free_f32(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_F32
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_F32
|
||||
float ffi_ironstorage_apple_rust_future_complete_f32(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_F64
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_F64
|
||||
void ffi_ironstorage_apple_rust_future_poll_f64(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_F64
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_F64
|
||||
void ffi_ironstorage_apple_rust_future_cancel_f64(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_F64
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_F64
|
||||
void ffi_ironstorage_apple_rust_future_free_f64(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_F64
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_F64
|
||||
double ffi_ironstorage_apple_rust_future_complete_f64(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_RUST_BUFFER
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_RUST_BUFFER
|
||||
void ffi_ironstorage_apple_rust_future_poll_rust_buffer(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_RUST_BUFFER
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_RUST_BUFFER
|
||||
void ffi_ironstorage_apple_rust_future_cancel_rust_buffer(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_RUST_BUFFER
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_RUST_BUFFER
|
||||
void ffi_ironstorage_apple_rust_future_free_rust_buffer(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_RUST_BUFFER
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_RUST_BUFFER
|
||||
RustBuffer ffi_ironstorage_apple_rust_future_complete_rust_buffer(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_VOID
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_POLL_VOID
|
||||
void ffi_ironstorage_apple_rust_future_poll_void(uint64_t handle, UniffiRustFutureContinuationCallback _Nonnull callback, uint64_t callback_data
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_VOID
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_CANCEL_VOID
|
||||
void ffi_ironstorage_apple_rust_future_cancel_void(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_VOID
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_FREE_VOID
|
||||
void ffi_ironstorage_apple_rust_future_free_void(uint64_t handle
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_VOID
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_RUST_FUTURE_COMPLETE_VOID
|
||||
void ffi_ironstorage_apple_rust_future_complete_void(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_FUNC_PRODUCT_NAME
|
||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_APPLE_CHECKSUM_FUNC_PRODUCT_NAME
|
||||
uint16_t uniffi_ironstorage_apple_checksum_func_product_name(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_UNIFFI_CONTRACT_VERSION
|
||||
#define UNIFFI_FFIDEF_FFI_IRONSTORAGE_APPLE_UNIFFI_CONTRACT_VERSION
|
||||
uint32_t ffi_ironstorage_apple_uniffi_contract_version(void
|
||||
|
||||
);
|
||||
#endif
|
||||
7
apple/Generated/ironstorage_appleFFI.modulemap
Normal file
7
apple/Generated/ironstorage_appleFFI.modulemap
Normal file
@@ -0,0 +1,7 @@
|
||||
module ironstorage_appleFFI {
|
||||
header "ironstorage_appleFFI.h"
|
||||
export *
|
||||
use "Darwin"
|
||||
use "_Builtin_stdbool"
|
||||
use "_Builtin_stdint"
|
||||
}
|
||||
32
apple/Info.plist
Normal file
32
apple/Info.plist
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>IronStorage</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>UILaunchScreen</key>
|
||||
<dict/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
1
apple/IronStorage-Bridging-Header.h
Normal file
1
apple/IronStorage-Bridging-Header.h
Normal file
@@ -0,0 +1 @@
|
||||
#include "Generated/ironstorage_appleFFI.h"
|
||||
20
apple/Sources/App/IronStorageApp.swift
Normal file
20
apple/Sources/App/IronStorageApp.swift
Normal file
@@ -0,0 +1,20 @@
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct IronStorageApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct ContentView: View {
|
||||
var body: some View {
|
||||
ContentUnavailableView(
|
||||
"No Password Store",
|
||||
systemImage: "lock.shield",
|
||||
description: Text("Open or clone a store in \(productName()) to begin.")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import AuthenticationServices
|
||||
|
||||
final class CredentialProviderViewController: ASCredentialProviderViewController {}
|
||||
10
apple/Sources/Watch/IronStorageWatchApp.swift
Normal file
10
apple/Sources/Watch/IronStorageWatchApp.swift
Normal file
@@ -0,0 +1,10 @@
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct IronStorageWatchApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentUnavailableView("No TOTP Codes", systemImage: "timer")
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apple/Watch-Info.plist
Normal file
26
apple/Watch-Info.plist
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>IronStorage</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>WKCompanionAppBundleIdentifier</key>
|
||||
<string>de.rfc1437.ironstorage</string>
|
||||
</dict>
|
||||
</plist>
|
||||
38
apple/build_rust_core.bash
Executable file
38
apple/build_rust_core.bash
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
export CARGO_TARGET_DIR="$DERIVED_FILE_DIR/cargo"
|
||||
export RUSTC="$(rustup which --toolchain stable rustc)"
|
||||
export RUSTDOC="$(rustup which --toolchain stable rustdoc)"
|
||||
|
||||
if [[ "$CONFIGURATION" == "Debug" ]]; then
|
||||
profile=debug
|
||||
else
|
||||
profile=release
|
||||
fi
|
||||
|
||||
libraries=()
|
||||
for arch in $ARCHS; do
|
||||
if [[ "$arch" == "arm64" && "${LLVM_TARGET_TRIPLE_SUFFIX:-}" == "-simulator" ]]; then
|
||||
target=aarch64-apple-ios-sim
|
||||
elif [[ "$arch" == "arm64" ]]; then
|
||||
target=aarch64-apple-ios
|
||||
elif [[ "$arch" == "x86_64" ]]; then
|
||||
target=x86_64-apple-ios
|
||||
else
|
||||
echo "Unsupported iOS architecture: $arch" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$profile" == "debug" ]]; then
|
||||
rustup run stable cargo build --locked \
|
||||
--target "$target" --package ironstorage-apple --lib
|
||||
else
|
||||
rustup run stable cargo build --locked --release \
|
||||
--target "$target" --package ironstorage-apple --lib
|
||||
fi
|
||||
libraries+=("$CARGO_TARGET_DIR/$target/$profile/libironstorage_apple.a")
|
||||
done
|
||||
|
||||
mkdir -p "$DERIVED_FILE_DIR/rust"
|
||||
lipo -create -output "$DERIVED_FILE_DIR/rust/libironstorage_apple.a" "${libraries[@]}"
|
||||
85
apple/project.yml
Normal file
85
apple/project.yml
Normal file
@@ -0,0 +1,85 @@
|
||||
name: IronStorage
|
||||
options:
|
||||
bundleIdPrefix: de.rfc1437
|
||||
settings:
|
||||
ENABLE_USER_SCRIPT_SANDBOXING: NO
|
||||
SWIFT_VERSION: "5.0"
|
||||
targets:
|
||||
IronStorage:
|
||||
type: application
|
||||
platform: iOS
|
||||
deploymentTarget: "17.0"
|
||||
settings:
|
||||
PRODUCT_BUNDLE_IDENTIFIER: de.rfc1437.ironstorage
|
||||
MARKETING_VERSION: "0.1.0"
|
||||
CURRENT_PROJECT_VERSION: "1"
|
||||
TARGETED_DEVICE_FAMILY: "1"
|
||||
SWIFT_OBJC_BRIDGING_HEADER: IronStorage-Bridging-Header.h
|
||||
LIBRARY_SEARCH_PATHS: "$(inherited) $(DERIVED_FILE_DIR)/rust"
|
||||
OTHER_LDFLAGS: "$(inherited) -lironstorage_apple"
|
||||
info:
|
||||
path: Info.plist
|
||||
properties:
|
||||
CFBundleDisplayName: IronStorage
|
||||
ITSAppUsesNonExemptEncryption: false
|
||||
UILaunchScreen: {}
|
||||
UISupportedInterfaceOrientations:
|
||||
- UIInterfaceOrientationPortrait
|
||||
sources:
|
||||
- Sources/App
|
||||
- Generated/ironstorage_apple.swift
|
||||
dependencies:
|
||||
- target: IronStorageAutoFill
|
||||
embed: true
|
||||
- target: IronStorageWatch
|
||||
embed: true
|
||||
preBuildScripts:
|
||||
- name: Build Rust core
|
||||
basedOnDependencyAnalysis: false
|
||||
script: |
|
||||
./build_rust_core.bash
|
||||
outputFiles:
|
||||
- $(DERIVED_FILE_DIR)/rust/libironstorage_apple.a
|
||||
IronStorageAutoFill:
|
||||
type: app-extension
|
||||
platform: iOS
|
||||
deploymentTarget: "17.0"
|
||||
settings:
|
||||
PRODUCT_BUNDLE_IDENTIFIER: de.rfc1437.ironstorage.autofill
|
||||
APPLICATION_EXTENSION_API_ONLY: YES
|
||||
SKIP_INSTALL: YES
|
||||
SWIFT_OBJC_BRIDGING_HEADER: IronStorage-Bridging-Header.h
|
||||
LIBRARY_SEARCH_PATHS: "$(inherited) $(DERIVED_FILE_DIR)/rust"
|
||||
OTHER_LDFLAGS: "$(inherited) -lironstorage_apple"
|
||||
info:
|
||||
path: AutoFill-Info.plist
|
||||
properties:
|
||||
CFBundleDisplayName: IronStorage AutoFill
|
||||
NSExtension:
|
||||
NSExtensionPointIdentifier: com.apple.authentication-services-credential-provider-ui
|
||||
NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).CredentialProviderViewController
|
||||
sources:
|
||||
- Sources/AutoFill
|
||||
- Generated/ironstorage_apple.swift
|
||||
preBuildScripts:
|
||||
- name: Build Rust core
|
||||
basedOnDependencyAnalysis: false
|
||||
script: |
|
||||
./build_rust_core.bash
|
||||
outputFiles:
|
||||
- $(DERIVED_FILE_DIR)/rust/libironstorage_apple.a
|
||||
IronStorageWatch:
|
||||
type: application
|
||||
platform: watchOS
|
||||
deploymentTarget: "10.0"
|
||||
settings:
|
||||
PRODUCT_BUNDLE_IDENTIFIER: de.rfc1437.ironstorage.watch
|
||||
PRODUCT_NAME: IronStorage Watch
|
||||
SKIP_INSTALL: YES
|
||||
info:
|
||||
path: Watch-Info.plist
|
||||
properties:
|
||||
CFBundleDisplayName: IronStorage
|
||||
WKCompanionAppBundleIdentifier: de.rfc1437.ironstorage
|
||||
sources:
|
||||
- Sources/Watch
|
||||
15
apps/cli/Cargo.toml
Normal file
15
apps/cli/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "ironstorage-cli"
|
||||
description = "Pass-compatible command-line frontend for IronStorage"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
publish = false
|
||||
|
||||
[[bin]]
|
||||
name = "ironstorage"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
clap.workspace = true
|
||||
ironstorage.workspace = true
|
||||
13
apps/cli/src/main.rs
Normal file
13
apps/cli/src/main.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(clippy::disallowed_types)]
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(version, about = "A pass-compatible password-store client")]
|
||||
struct Arguments {}
|
||||
|
||||
fn main() {
|
||||
Arguments::parse();
|
||||
println!("{}", ironstorage::PRODUCT_NAME);
|
||||
}
|
||||
15
apps/desktop/Cargo.toml
Normal file
15
apps/desktop/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "ironstorage-desktop"
|
||||
description = "Iced desktop frontend for IronStorage"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
publish = false
|
||||
|
||||
[[bin]]
|
||||
name = "ironstorage-desktop"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
iced.workspace = true
|
||||
ironstorage.workspace = true
|
||||
23
apps/desktop/src/main.rs
Normal file
23
apps/desktop/src/main.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(clippy::disallowed_types)]
|
||||
|
||||
use iced::{Element, Length, widget::container, widget::text};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Message {}
|
||||
|
||||
fn main() -> iced::Result {
|
||||
iced::application(|| (), update, view)
|
||||
.title(ironstorage::PRODUCT_NAME)
|
||||
.run()
|
||||
}
|
||||
|
||||
fn update(_: &mut (), message: Message) {
|
||||
match message {}
|
||||
}
|
||||
|
||||
fn view(_: &()) -> Element<'_, Message> {
|
||||
container(text("No password store is open."))
|
||||
.center(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
16
apps/tui/Cargo.toml
Normal file
16
apps/tui/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "ironstorage-tui"
|
||||
description = "Ratatui frontend for IronStorage"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
publish = false
|
||||
|
||||
[[bin]]
|
||||
name = "ironstorage-tui"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
crossterm.workspace = true
|
||||
ironstorage.workspace = true
|
||||
ratatui.workspace = true
|
||||
49
apps/tui/src/main.rs
Normal file
49
apps/tui/src/main.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(clippy::disallowed_types)]
|
||||
|
||||
use std::io;
|
||||
|
||||
use crossterm::event::{self, Event, KeyCode};
|
||||
use ratatui::{
|
||||
DefaultTerminal, Frame,
|
||||
widgets::{Block, Paragraph},
|
||||
};
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
ratatui::run(run)
|
||||
}
|
||||
|
||||
fn run(terminal: &mut DefaultTerminal) -> io::Result<()> {
|
||||
loop {
|
||||
terminal.draw(draw)?;
|
||||
if let Event::Key(key) = event::read()?
|
||||
&& is_quit(key.code)
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(frame: &mut Frame) {
|
||||
frame.render_widget(
|
||||
Paragraph::new("No password store is open. Press q to quit.")
|
||||
.block(Block::bordered().title(ironstorage::PRODUCT_NAME)),
|
||||
frame.area(),
|
||||
);
|
||||
}
|
||||
|
||||
fn is_quit(key: KeyCode) -> bool {
|
||||
matches!(key, KeyCode::Char('q') | KeyCode::Esc)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crossterm::event::KeyCode;
|
||||
|
||||
#[test]
|
||||
fn q_and_escape_quit() {
|
||||
assert!(super::is_quit(KeyCode::Char('q')));
|
||||
assert!(super::is_quit(KeyCode::Esc));
|
||||
assert!(!super::is_quit(KeyCode::Enter));
|
||||
}
|
||||
}
|
||||
4
clippy.toml
Normal file
4
clippy.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
disallowed-types = [
|
||||
{ path = "std::process::Child", reason = "IronStorage must not launch external processes" },
|
||||
{ path = "std::process::Command", reason = "IronStorage must not launch external processes" },
|
||||
]
|
||||
15
crates/apple/Cargo.toml
Normal file
15
crates/apple/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "ironstorage-apple"
|
||||
description = "UniFFI boundary between IronStorage and its Apple frontends"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "ironstorage_apple"
|
||||
crate-type = ["lib", "staticlib", "cdylib"]
|
||||
|
||||
[dependencies]
|
||||
ironstorage.workspace = true
|
||||
uniffi.workspace = true
|
||||
19
crates/apple/src/lib.rs
Normal file
19
crates/apple/src/lib.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(clippy::disallowed_types)]
|
||||
|
||||
//! Mechanical UniFFI exports for Apple presentation code.
|
||||
|
||||
uniffi::setup_scaffolding!();
|
||||
|
||||
#[uniffi::export]
|
||||
pub fn product_name() -> String {
|
||||
ironstorage::PRODUCT_NAME.to_owned()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn bridge_reads_product_name_from_storage_crate() {
|
||||
assert_eq!(super::product_name(), ironstorage::PRODUCT_NAME);
|
||||
}
|
||||
}
|
||||
7
crates/storage/Cargo.toml
Normal file
7
crates/storage/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "ironstorage"
|
||||
description = "Pure Rust password-store repository management"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
publish = false
|
||||
9
crates/storage/src/lib.rs
Normal file
9
crates/storage/src/lib.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(clippy::disallowed_types)]
|
||||
|
||||
//! Password-store repository behavior shared by every IronStorage frontend.
|
||||
//!
|
||||
//! This crate is the sole owner of stored and derived password-store objects.
|
||||
|
||||
/// Product name shared by the presentation adapters.
|
||||
pub const PRODUCT_NAME: &str = "IronStorage";
|
||||
Reference in New Issue
Block a user