Skip to content

Instantly share code, notes, and snippets.

View groue's full-sized avatar

Gwendal Roué groue

View GitHub Profile
@groue
groue / CategoryButton.swift
Created February 11, 2025 16:30
A SwiftUI button that looks like a category button in the Reminders app.
import SwiftUI
// MARK: - CategoryButton
/// A button that looks like a category button in the Reminders app.
///
/// ╭─────────────╮
/// │ (•) 12 │
/// │ │
/// │ Title │
@groue
groue / BalancedLayout.swift
Last active February 10, 2025 16:09
A SwiftUI layout for balancing text
import SwiftUI
/// A layout that shrinks the width of its content as much as possible,
/// without increasing its height.
///
/// It is a layout suitable for balancing text. Compare the normal and
/// balanced texts below: they have the same number of lines, but the
/// balanced version is less wide and looks more balanced:
///
/// │Ça a débuté comme ça. Moi, j'avais jamais|
@groue
groue / Observation+Utils.swift
Last active January 22, 2025 20:01
Observation+Utils.swift
import Combine
import Dispatch
import Foundation
import Observation
/// A LockedValue protects a value with an NSLock.
private final class LockedValue<T> {
private var value: T
private var lock = NSLock()
@groue
groue / ObservableState.swift
Last active February 6, 2025 11:12
WithBindable
// Copyright (C) 2024 Gwendal Roué
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
@groue
groue / SynchronizationQueue.swift
Created February 14, 2024 13:12
A Swift concurrency queue that I find useful when dealing with synchronization.
import Semaphore
/// The priority of an operation started by `SynchronizationQueue`.
enum SynchronizationPriority {
/// An operation with `required` priority is not cancelled by
/// subsequent operations.
case required
/// Intended for "pull-to-refresh": an operation with `refresh` priority
/// is cancelled by subsequent operations started with the `refresh` or
@groue
groue / Trigger.swift
Created February 14, 2024 12:27
A Trigger type that helps SwiftUI views control when cancellable async jobs are run.
import SwiftUI
extension View {
/// Adds a task to perform before this view appears or when the trigger
/// is fired.
///
/// This method behaves like `View.task(id:priority:_:)`, except that it
/// cancels and recreates the task when the `fire` method of the
/// trigger is called.
///
@groue
groue / JSONSupportTests.swift
Created October 7, 2023 09:28
Test JSON support
import XCTest
import GRDB
class JSONSupportTests: GRDBTestCase {
func testJSONSupport() throws {
let queries = [
#"select json('[]') = '[]';"#,
#"select json_array() = '[]';"#,
#"select json_array_length('[]') = 0;"#,
#"select json_array_length('[[]]','$[0]') = 0;"#,
@groue
groue / opinion.md
Last active September 7, 2023 14:59
Swift key paths are not coding keys, JSON keys, or SQLite columns

Swift key paths are not coding keys, JSON keys, or SQLite columns

(Copy-pasted from groue/GRDB.swift#1423 (comment), edited for clarity)

And if I remember correctly, you had some good reasons for not using key paths in the GRDB query builder

My reluctance about key paths is based on the fact that record types do frequently, but not always, exactly reflect their database representation. The reality is that record types are a Swift interface to their inner database representation. And it's the same for "json records" as well.

That's how people use them. They'll replace a text database value with a Swift string-based enum value. They'll publicly expose a price: Decimal property instead of the priceCents database integer. They'll publicly expose a location: CLLocationCoordinate2D property instead of two latitude and longitude database doubles.

@groue
groue / transcript.md
Last active March 26, 2023 13:05
ChatGPT attempts at implementing a counting semaphore with Swift Concurrency

Is it possible to implement a classical counting semaphore with Swift concurrency (async/await)? I wish I could call an async method await semaphore.wait() and a sync method semaphore.signal() with the same semantics as a classical semaphore, but without blocking any thread.

Yes, it is possible to implement a classical counting semaphore with Swift concurrency using async/await without blocking any thread. Here is an example implementation: swift

class Semaphore {
    private var count: Int
    private let lock = NSLock()
    private var waiters: [Task<Void, Never>] = []
@groue
groue / TimestampedRecord.swift
Last active February 21, 2023 07:09
TimestampedRecord: an example protocol for GRDB records that track their creation and modification dates.
/// A type that tracks its creation and modification dates, as described in
/// <https://swiftpackageindex.com/groue/grdb.swift/documentation/grdb/recordtimestamps>
protocol TimestampedRecord {
var creationDate: Date? { get set }
var modificationDate: Date? { get set }
}
extension TimestampedRecord where Self: MutablePersistableRecord {
/// Sets `modificationDate` to the transaction date.
mutating func touch(_ db: Database) throws {