Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions core-tests/shared/src/test/scala/zio/RefSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,127 @@ object RefSpec extends ZIOBaseSpec {
case Changed => Closed
}
} yield assert(value1)(equalTo(Changed)) && assert(value2)(equalTo(Closed))
},
test("getAndIncrement[Int]") {
for {
ref <- Ref.make(1)
value1 <- ref.getAndIncrement
value2 <- ref.get
} yield assertTrue(value1 == 1, value2 == 2)
},
test("getAndIncrement[Long]") {
for {
ref <- Ref.make(1L)
value1 <- ref.getAndIncrement
value2 <- ref.get
} yield assertTrue(value1 == 1L, value2 == 2L)
},
test("getAndDecrement[Int]") {
for {
ref <- Ref.make(1)
value1 <- ref.getAndDecrement
value2 <- ref.get
} yield assertTrue(value1 == 1, value2 == 0)
},
test("getAndDecrement[Long]") {
for {
ref <- Ref.make(1L)
value1 <- ref.getAndDecrement
value2 <- ref.get
} yield assertTrue(value1 == 1L, value2 == 0L)
},
test("getAndAdd[Int]") {
for {
ref <- Ref.make(1)
value1 <- ref.getAndAdd(10)
value2 <- ref.get
} yield assertTrue(value1 == 1, value2 == 11)
},
test("getAndAdd[Long]") {
for {
ref <- Ref.make(1L)
value1 <- ref.getAndAdd(10)
value2 <- ref.getAndAdd(20L)
value3 <- ref.get
} yield assertTrue(value1 == 1L, value2 == 11L, value3 == 31L)
},
test("incrementAndGet[Int]") {
for {
ref <- Ref.make(1)
value <- ref.incrementAndGet
} yield assertTrue(value == 2)
},
test("incrementAndGet[Long]") {
for {
ref <- Ref.make(1L)
value <- ref.incrementAndGet
} yield assertTrue(value == 2L)
},
test("decrementAndGet[Int]") {
for {
ref <- Ref.make(1)
value <- ref.decrementAndGet
} yield assertTrue(value == 0)
},
test("decrementAndGet[Long]") {
for {
ref <- Ref.make(1L)
value <- ref.decrementAndGet
} yield assertTrue(value == 0L)
},
test("addAndGet[Int]") {
for {
ref <- Ref.make(1)
value <- ref.addAndGet(10)
} yield assertTrue(value == 11)
},
test("addAndGet[Long]") {
for {
ref <- Ref.make(1L)
value1 <- ref.addAndGet(10)
value2 <- ref.addAndGet(20L)
} yield assertTrue(value1 == 11L, value2 == 31L)
},
test("incrementAndGet[Byte]") {
for {
ref <- Ref.make(1.toByte)
value <- ref.incrementAndGet
} yield assertTrue(value == 2.toByte)
},
test("incrementAndGet[Char]") {
for {
ref <- Ref.make(1.toChar)
value <- ref.incrementAndGet
} yield assertTrue(value == 2.toChar)
},
test("incrementAndGet[Short]") {
for {
ref <- Ref.make(1.toShort)
value <- ref.incrementAndGet
} yield assertTrue(value == 2.toShort)
},
test("incrementAndGet[Double]") {
for {
ref <- Ref.make(1.0d)
value <- ref.incrementAndGet
} yield assertTrue(value == 2.0d)
},
test("incrementAndGet[Float]") {
for {
ref <- Ref.make(1.0f)
value <- ref.incrementAndGet
} yield assertTrue(value == 2.0f)
},
test("incrementAndGet[BigInt]") {
for {
ref <- Ref.make(BigInt(1))
value <- ref.incrementAndGet
} yield assertTrue(value == BigInt(2))
},
test("Ref[String].incrementAndGet does not compile") {
val result = typeCheck(""" Ref.make("").incrementAndGet """)
val expected = "value incrementAndGet is not a member of zio.UIO[zio.Ref[String]]"
assertZIO(result)(isLeft(startsWithString(expected)))
}
)
)
Expand Down
43 changes: 43 additions & 0 deletions core/shared/src/main/scala/zio/Ref.scala
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,49 @@ abstract class Ref[A] extends Serializable {
val result = pf.applyOrElse[A, A](v, identity)
(result, result)
}

/**
* Atomically increments the current value of the `Ref` by 1, returning the
* value immediately before modification.
*/
final def getAndIncrement(implicit num: math.Numeric[A], trace: Trace): UIO[A] =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it wise to mark them as final? I suppose a specialized version won't have the implicit argument anyway, so maybe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making them non-final is fully backwards compatible, so maybe we can start with having them as final and we can change them when needed

getAndUpdate(v => num.plus(v, num.one))

/**
* Atomically decrements the current value of the `Ref` by 1, returning the
* value immediately before modification.
*/
final def getAndDecrement(implicit num: math.Numeric[A], trace: Trace): UIO[A] =
getAndUpdate(v => num.minus(v, num.one))

/**
* Atomically adds `delta` to the current value of the `Ref`, returning the
* value immediately before modification.
*/
final def getAndAdd(delta: A)(implicit num: math.Numeric[A], trace: Trace): UIO[A] =
getAndUpdate(v => num.plus(v, delta))

/**
* Atomically increments the current value of the `Ref` by 1 and returns the
* updated value.
*/
final def incrementAndGet(implicit num: math.Numeric[A], trace: Trace): UIO[A] =
updateAndGet(v => num.plus(v, num.one))

/**
* Atomically decrements the current value of the `Ref` by 1 and returns the
* updated value.
*/
final def decrementAndGet(implicit num: math.Numeric[A], trace: Trace): UIO[A] =
updateAndGet(v => num.minus(v, num.one))

/**
* Atomically adds `delta` to the current value of the `Ref` and returns the
* updated value.
*/
final def addAndGet(delta: A)(implicit num: math.Numeric[A], trace: Trace): UIO[A] =
updateAndGet(v => num.plus(v, delta))

}

object Ref extends Serializable {
Expand Down
Loading