@@ -17,7 +17,10 @@ package com.diffplug.selfie
1717
1818import com.diffplug.selfie.guts.CallStack
1919import com.diffplug.selfie.guts.DiskStorage
20+ import com.diffplug.selfie.guts.atomic
2021import com.diffplug.selfie.guts.recordCall
22+ import com.diffplug.selfie.guts.reentrantLock
23+ import com.diffplug.selfie.guts.withLock
2124
2225private const val OPEN = " «"
2326private const val CLOSE = " »"
@@ -32,29 +35,34 @@ internal constructor(
3235 private val call = recordCall(false )
3336 fun createVcr () = VcrSelfie (sub, call, disk)
3437 }
38+ private val state: State
3539
3640 internal sealed class State {
3741 class Read (val frames : List <Pair <String , SnapshotValue >>) : State() {
38- var currentFrame = 0
42+ fun currentFrameThenAdvance (): Int = cf.getAndUpdate { it + 1 }
43+ fun framesReadSoFar (): Int = cf.get()
44+ private val cf = atomic(0 )
3945 }
4046
4147 class Write : State () {
42- private val frames = mutableListOf<Pair <String , SnapshotValue >>()
48+ private val lock = reentrantLock()
49+ private var frames: MutableList <Map .Entry <String , SnapshotValue >>? =
50+ mutableListOf<Map .Entry <String , SnapshotValue >>()
4351 fun add (key : String , value : SnapshotValue ) {
44- frames.add(key to value)
45- }
46- fun toSnapshot (): Snapshot {
47- var snapshot = Snapshot .of(" " )
48- var idx = 1
49- for ((key, value) in frames) {
50- snapshot = snapshot.plusFacet(" $OPEN$idx$CLOSE$key " , value)
51- ++ idx
52+ lock.withLock {
53+ frames?.add(entry(key, value))
54+ ? : throw IllegalStateException (" This VCR was already closed." )
5255 }
53- return snapshot
5456 }
57+ fun closeAndGetSnapshot (): Snapshot =
58+ Snapshot .ofEntries(
59+ lock.withLock {
60+ val frozen = frames ? : throw IllegalStateException (" This VCR was already closed." )
61+ frames = null
62+ frozen
63+ })
5564 }
5665 }
57- private val state: State
5866
5967 init {
6068 val canWrite = Selfie .system.mode.canWrite(isTodo = false , call, Selfie .system)
@@ -81,24 +89,25 @@ internal constructor(
8189 }
8290 override fun close () {
8391 if (state is State .Read ) {
84- if (state.frames.size != state.currentFrame ) {
92+ if (state.frames.size != state.framesReadSoFar() ) {
8593 throw Selfie .system.fs.assertFailed(
86- Selfie .system.mode.msgVcrUnread(state.frames.size, state.currentFrame ))
94+ Selfie .system.mode.msgVcrUnread(state.frames.size, state.framesReadSoFar() ))
8795 }
8896 } else {
89- disk.writeDisk((state as State .Write ).toSnapshot (), sub, call)
97+ disk.writeDisk((state as State .Write ).closeAndGetSnapshot (), sub, call)
9098 }
9199 }
92100 private fun nextFrameValue (state : State .Read , key : String ): SnapshotValue {
93101 val mode = Selfie .system.mode
94102 val fs = Selfie .system.fs
95- if (state.frames.size <= state.currentFrame) {
103+ val currentFrame = state.currentFrameThenAdvance()
104+ if (state.frames.size <= currentFrame) {
96105 throw fs.assertFailed(mode.msgVcrUnderflow(state.frames.size))
97106 }
98- val expected = state.frames[state. currentFrame++ ]
107+ val expected = state.frames[currentFrame]
99108 if (expected.first != key) {
100109 throw fs.assertFailed(
101- mode.msgVcrMismatch(" $sub [$OPEN${state. currentFrame}$CLOSE ]" , expected.first, key),
110+ mode.msgVcrMismatch(" $sub [$OPEN${currentFrame}$CLOSE ]" , expected.first, key),
102111 expected.first,
103112 key)
104113 }
0 commit comments