This commit is contained in:
Leif 2023-03-06 16:54:38 -07:00
commit e4dbd93c3c
9 changed files with 280 additions and 0 deletions

22
.github/CI.yml vendored Normal file
View File

@ -0,0 +1,22 @@
# This workflow will build a Swift project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift
name: CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Build
run: swift build -v
- name: Run tests
run: swift test -v

37
.github/docc.yml vendored Normal file
View File

@ -0,0 +1,37 @@
name: docc
on:
push:
branches: ["main"]
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
pages:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: macos-12
steps:
- name: git checkout
uses: actions/checkout@v3
- name: docbuild
run: |
xcodebuild docbuild -scheme Cache \
-derivedDataPath /tmp/docbuild \
-destination 'generic/platform=iOS';
$(xcrun --find docc) process-archive \
transform-for-static-hosting /tmp/docbuild/Build/Products/Debug-iphoneos/Cache.doccarchive \
--hosting-base-path Cache \
--output-path docs;
echo "<script>window.location.href += \"/documentation/cache\"</script>" > docs/index.html;
- name: artifacts
uses: actions/upload-pages-artifact@v1
with:
path: 'docs'
- name: deploy
id: deployment
uses: actions/deploy-pages@v1

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

23
Package.resolved Normal file
View File

@ -0,0 +1,23 @@
{
"pins" : [
{
"identity" : "c",
"kind" : "remoteSourceControl",
"location" : "https://github.com/0xOpenBytes/c",
"state" : {
"revision" : "876899c63377f407a27316ce24eb7bc37653cb13",
"version" : "4.0.0"
}
},
{
"identity" : "t",
"kind" : "remoteSourceControl",
"location" : "https://github.com/0xOpenBytes/t",
"state" : {
"revision" : "c111675ac4d84af23d2d9b65bffaf1829c376986",
"version" : "1.0.4"
}
}
],
"version" : 2
}

37
Package.swift Normal file
View File

@ -0,0 +1,37 @@
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Cache",
platforms: [
.iOS(.v14),
.macOS(.v11),
.watchOS(.v7),
.tvOS(.v14)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "Cache",
targets: ["Cache"]
)
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/0xOpenBytes/c", from: "4.0.0")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "Cache",
dependencies: ["c"]
),
.testTarget(
name: "CacheTests",
dependencies: ["Cache"]
)
]
)

26
README.md Normal file
View File

@ -0,0 +1,26 @@
# Cache
Cache is a simple in-memory key-value store that provides thread-safe access to its contents. It is used for storing frequently used data that takes time or resources to compute. When a value is added to the cache, it is stored in memory and can be retrieved quickly on subsequent accesses.
## Usage
To use the Cache, first create an instance with the desired key and value types. You can then use the set(_:forKey:) method to add items to the cache, and the get(_:) method to retrieve items from the cache.
```swift
let cache = Cache<String, Int>()
cache.set(42, forKey: "answer")
let answer = cache.get("answer") // answer == 42
```
The Cache also supports removal of items from the cache using the remove(_:) method. To remove all items from the cache, use the clear() method.
```swift
let cache = Cache<String, Int>()
cache.set(42, forKey: "answer")
cache.remove("answer")
let answer = cache.get("answer") // answer == nil
```
### Thread Safety
The Cache is designed to be thread-safe, allowing multiple threads to access and modify the cache without the risk of data races.

14
Sources/Cache/Cache.swift Normal file
View File

@ -0,0 +1,14 @@
import c
/**
A convenience subclass of `c.Cache`.
To use the cache, create an instance of `Cache` with the desired key and value types. You can then use the `set(_:forKey:)` method to add items to the cache, and the `get(_:)` or `resolve(_:)` method to retrieve items from the cache.
```swift
let cache = Cache<String, Int>()
cache.set(42, forKey: "answer")
let answer = cache.get("answer") // answer == 42
```
*/
open class Cache<Key: Hashable, Value>: c.Cache<Key, Value> { }

19
Sources/Cache/JSON.swift Normal file
View File

@ -0,0 +1,19 @@
import c
/**
`JSON` is a generic struct that provides a convenient way to parse and manipulate JSON data. It uses the `c` library to parse and serialize JSON data.
To create a `JSON` object, pass a `Data` object that contains JSON data to the `init(data:)` method. You can then use the `get(_:)` or `resolve(_:)` method to extract individual values from the JSON data.
let jsonData = "{\"name\": \"John Doe\", \"age\": 42}".data(using: .utf8)!
let json = JSON<MockJSONKey>(data: jsonData)
let name: String = try json.resolve(.name)
let age: Int = try json.resolve(.age)
You can also use the `set(value:forKey:)` method to update the values in the JSON object, and the `get(_:)` or `resolve(_:)` method to retrieve the values from the object.
json.set(value: "Jane Doe", forKey: .name)
let newName: String = try json.resolve(.name)
*/
public typealias JSON = c.JSON

View File

@ -0,0 +1,93 @@
import SwiftUI
import XCTest
@testable import Cache
final class CacheTests: XCTestCase {
func testCacheString() throws {
enum CacheKey {
case text
}
let cache: Cache<CacheKey, String> = Cache(
initialValues: [
.text: "Hello, World!"
]
)
let cachedValue: String = try XCTUnwrap(cache.get(.text))
XCTAssertEqual(cachedValue, "Hello, World!")
}
func testCacheImage() throws {
let cache: Cache<URL, Image> = Cache()
let imageURL = try XCTUnwrap(URL(string: "test-image"))
XCTAssertNil(cache.get(imageURL))
cache.set(value: Image(systemName: "circle"), forKey: imageURL)
XCTAssertNotNil(cache.get(imageURL))
cache.remove(imageURL)
XCTAssertNil(cache.get(imageURL))
}
func testCacheObjectInheritance() throws {
class ParentObject {
let value: String
init(value: String) {
self.value = value
}
}
class SubclassObject: ParentObject { }
let expectedValue = "subclass"
let key = UUID()
let cache: Cache<AnyHashable, ParentObject> = Cache()
cache.set(value: SubclassObject(value: expectedValue), forKey: key)
let subclassObject: SubclassObject = try XCTUnwrap(cache.get(key))
XCTAssertEqual(subclassObject.value, expectedValue)
}
func testJSON() throws {
enum MockJSONKey: String, Hashable {
case name, number, bool, invalid_key
}
struct MockJSON: Codable {
var name: String
var number: Int
var bool: Bool
}
let jsonData: Data = try! JSONEncoder().encode(MockJSON(name: "OpenBytes", number: 5, bool: false))
var json: JSON<MockJSONKey> = JSON(data: jsonData)
XCTAssertEqual(try json.resolve(.name), "OpenBytes")
XCTAssertEqual(try json.resolve(.number), 5)
XCTAssertEqual(try json.resolve(.bool), false)
XCTAssertEqual(json.valuesInCache(ofType: String.self).count, 1)
XCTAssertEqual(json.valuesInCache(ofType: Int.self).count, 2)
XCTAssertEqual(json.valuesInCache(ofType: Bool.self).count, 1)
let invalid_key: Bool? = json.get(.invalid_key)
XCTAssertNil(json.get(.invalid_key))
XCTAssertNil(invalid_key)
json.set(value: "Leif", forKey: .name)
XCTAssertEqual(try json.resolve(.name), "Leif")
}
}