ぜのぜ

しりとりしようぜのぜのぜのぜ

612日目

日記

今日書いたコード

unicode scalarを読むことにした · Gurrium/SwiftKilo@a8e0312 · GitHub

感想

昨日最悪な気分になりながら寝ようとしたら、unicode scalarをそのまま読めばいいのでは?と思いついた。どうせ表示する時はStringに入れるわけだし問題ないはず。SwiftのStringのカウントはextended grapheme cluster単位だから消すときも多分大丈夫。

611日目

日記

今日書いたコード

使えそうなプロパティのテストを書いた · Gurrium/SwiftKilo@31d1555 · GitHub

感想

charactersを使ってみたが次のクラスタを入力するまで読めないのが回避できなかったのでbytesを使ってみることにした…あれ??より退化してない??アホくさくなってきたのでもう諦めようかな。

610日目

日記

今日書いたコード

charactersを使う · Gurrium/SwiftKilo@c4be96b · GitHub

感想

https://developer.apple.com/documentation/foundation/filehandle/asyncbytes/3766657-characters で良かった。ただ次の文字を入力しないと読んでくれないのでタイムアウトは自分で実装する必要がある。

イテレータをラップするかstdinに\0を入れるか?

609日目

日記

今日書いたコード

困りを再現するテストを書いた · Gurrium/ReadGraphemeCluster@8d2f4ab · GitHub

感想

"ここ"がないとスタックする。FileHandle.bytes.unicodeScalarsをfor-awaitで待つとタスクがキャンセルされてもawaitで待ち続けるっぽい。(もしくは、awaitで待ち続けるのでタスクがキャンセルされない?)

1つのgrapheme clusterを入力したあとにタイムアウトするようにコードを書いているので、scalarを読むたびにタウムアウトする以上に待つ必要があると複数のscalarからなるgrapheme clusterを読めなくなる。

適当なAsyncSequenceを実装すると同じところでスタックしなかったのでFileHandle.bytes.unicodeScalarsの実装が悪いのかも。

actor Flag {
    var content: Bool

    init(content: Bool) {
        self.content = content
    }

    func set(_ content: Bool) {
        self.content = content
    }
}

func test_cancellingTask() async throws {
    let pipe = Pipe()
    let handle = pipe.fileHandleForReading
    let flag = Flag(content: true)

    try pipe.fileHandleForWriting.write(contentsOf: Array("a".utf8))

    let groupResult = try await withThrowingTaskGroup(of: Bool.self) { group in
        group.addTask {
             for try await scalar in handle.bytes.unicodeScalars {
            // var it = handle.bytes.unicodeScalars.makeAsyncIterator()
            // while let scalar = try await it.next() { // これでも同じ
                print(scalar)
                await flag.set(false)
                try await Task.sleep(nanoseconds: 50_000) // ここ
            }

            return true
        }

        group.addTask {
            while await flag.content {
                try await Task.sleep(nanoseconds: 1_000)
            }

            print("timeout")
            return false
        }

        let ret = try await group.next()!
        group.cancelAll()
        XCTAssertFalse(try XCTUnwrap(ret))

        return ret
    }

    print("groupResult:", groupResult)
}

ところでFileHandle.bytes.characters*1が生えてたので終わり。あほくさ。

608日目

日記

今日書いたコード

WIP!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! · Gurrium/ReadGraphemeCluster@d009232 · GitHub

感想

"ここ"が呼ばれるまでwithThrowingTaskGroupがスタックしてそうで詰まっている。

// [https://github.com/Gurrium/ReadGraphemeCluster/commit/d009232e69d957413022f07ae7df1e8710e93da8#diff-102f0c74b4bceb38182a3d1f4823344c81ab3d0d92662ce8f740d1f595889185R154]
withThrowingTaskGroup { taskGroup in
    for try await scalar in fileHandle.bytes.unicodeScalars {
        if Task.isCancelled {
            return nil // ここ
        }
    // ...
    }

    // ...
    taskGroup.cancelAll()
    // ...
}

こうあるのでcancelAll()を呼べばいいと思うんだが…

A group waits for all of its child tasks to complete, throw an error, or be canceled before it returns https://developer.apple.com/documentation/swift/withthrowingtaskgroup(of:returning:body:)#discussion

飽きたので終わり。

606日目

日記

今日書いたコード

matchのバグを修正した · Gurrium/ReadGraphemeCluster@26750a3 · GitHub

感想

.anyよりあとにしたやつは使われていないやつなので、GraphemeClusterBreak.allCases.first { $0.match(scalar) }!としたときに先にmatchしてほしい。あまり筋がよくないと思う。

他にも色々やったけど駄目だった。疲れた。