Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement strings API in test executor #511

Merged
merged 3 commits into from
Feb 16, 2022
Merged

Conversation

mvelimir
Copy link
Collaborator

@mvelimir mvelimir commented Jan 3, 2022

Resolves #198
BITFIELD not yet implemented

@jdegoes
Copy link
Member

jdegoes commented Jan 5, 2022

Looks really great! Would be good to have some tests for the new operations to make sure they are working as specified.

@mijicd
Copy link
Member

mijicd commented Jan 13, 2022

@mvelimir Please resolve the conflicts.

@mijicd
Copy link
Member

mijicd commented Feb 6, 2022

@mvelimir Is this still work in progress? If not, please convert it to a pull request :)

@mvelimir
Copy link
Collaborator Author

mvelimir commented Feb 6, 2022

There's still the BITFIELD command left to be implemented, but I could make a separate PR for that.

@mvelimir mvelimir marked this pull request as ready for review February 6, 2022 15:51
@mvelimir mvelimir requested a review from a team as a code owner February 6, 2022 15:51
@mijicd
Copy link
Member

mijicd commented Feb 6, 2022

@mvelimir I agree, let's have it in a separate PR. Please rebase this one, and I'll review it immediately.

Copy link
Member

@mijicd mijicd left a comment

Choose a reason for hiding this comment

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

First pass done.

Comment on lines 3000 to 3001
Try(start.getOrElse("0").toInt).toOption.fold[RespValue](Replies.Error) { start =>
Try(end.getOrElse(string.length.toString).toInt).toOption.fold[RespValue](Replies.Error) { end =>
Copy link
Member

Choose a reason for hiding this comment

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

Let's unnest this a bit, e.g.

val resp =
  for {
    bit   <- Option.when(bit == "0" || bit == "1") // you'll need a helper since this is 2.13 function
    start <- start.map(start => Try(start.toInt).toOption).orElse(Some(0))
    end   <- end.map(end => Try(end.toInt).toOption).orElse(Some(string.length))
    // the rest of calculation
  } yield value

resp.getOrElse(Replies.Error)

Consider creating a helper for int conversion if there isn't one already. Once you have it, replace the other parsing occurrences.


val index = string.zipWithIndex
.slice(newStart, newEnd)
.map(tuple => f"${tuple._1.asInstanceOf[Int].toBinaryString}%8s".replace(' ', '0') -> tuple._2)
Copy link
Member

Choose a reason for hiding this comment

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

Let's get rid of asInstanceOf.

Comment on lines 3048 to 3053
Try(stringOption.getOrElse("0").toLong).toOption.fold(STM.succeed(Replies.Error: RespValue)) { num =>
if (decr >= 0 && num >= Long.MinValue + decr || decr < 0 && num <= Long.MaxValue + decr) {
val result = num - decr

putString(key, result.toString).as(RespValue.Integer(result))
} else STM.succeed(Replies.Error)
Copy link
Member

Choose a reason for hiding this comment

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

Simplify as suggested above.

Comment on lines 3030 to 3036
Try(stringOption.getOrElse("0").toLong).toOption.fold(STM.succeed(Replies.Error: RespValue)) { num =>
if (num > Long.MinValue) {
val result = num - 1

putString(key, result.toString).as(RespValue.Integer(result))
} else STM.succeed(Replies.Error)
}
Copy link
Member

Choose a reason for hiding this comment

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

Simplify as suggested above.

Comment on lines 3065 to 3066
strings.getOrElse(key, "").map { string =>
Try(offset.toInt).toOption.filter(_ >= 0).fold[RespValue](Replies.Error) { offset =>
RespValue
.Integer(string.getBytes.lift(offset / 8).fold(0L)(byte => (byte >> (7 - offset % 8) & 1).toLong))
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Ditto.

Comment on lines 3081 to 3087
strings.getOrElse(key, "").map { string =>
Try(start.toInt).toOption
.flatMap(a => Try(end.toInt).toOption.map(b => (a, b)))
.fold[RespValue](Replies.Error) { range =>
val newStart = if (range._1 < 0) string.length + range._1 else range._1
val newEnd = (if (range._2 < 0) string.length + range._2 else range._2) + 1

RespValue.bulkString(string.slice(newStart, newEnd))
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Ditto

Comment on lines 3114 to 3118
if (num < Long.MaxValue) {
val result = num + 1

putString(key, result.toString).as(RespValue.Integer(result))
} else STM.succeed(Replies.Error)
Copy link
Member

Choose a reason for hiding this comment

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

You can use ZSTM.cond

Comment on lines 3130 to 3139
strings.getOrElse(key, "0").flatMap { string =>
Try(string.toLong).toOption.fold(STM.succeed(Replies.Error: RespValue)) { num =>
Try(incr.toLong).toOption.fold(STM.succeed(Replies.Error: RespValue)) { incr =>
if (incr >= 0 && num <= Long.MaxValue - incr || incr < 0 && num >= Long.MinValue - incr) {
val result = num + incr

putString(key, result.toString).as(RespValue.Integer(result))
} else STM.succeed(Replies.Error)
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Simplify as suggested above.

Comment on lines 3151 to 3158
Try(string.toDouble).toOption.fold(STM.succeed(Replies.Error: RespValue)) { num =>
Try(incr.toDouble).toOption.fold(STM.succeed(Replies.Error: RespValue)) { incr =>
if (incr >= 0 && num <= Double.MaxValue - incr || incr < 0 && num >= Double.MinValue - incr) {
val result = (num + incr).toString

putString(key, result).as(RespValue.bulkString(result))
} else STM.succeed(Replies.Error)
}
Copy link
Member

Choose a reason for hiding this comment

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

Simplify as suggested above.

Comment on lines 3328 to 3342
Try(offset.toInt).toOption.filter(_ >= 0).fold[USTM[RespValue]](STM.succeed(Replies.Error)) { offset =>
Try(value.toInt).toOption
.filter(num => num == 0 || num == 1)
.fold[USTM[RespValue]](STM.succeed(Replies.Error)) { value =>
val newString = string + "\u0000" * (offset / 8 + 1 - string.length)

newString.lift(offset / 8).fold(STM.succeed(Replies.Error: RespValue)) { char =>
val resp = (char >> (7 - offset % 8) & 1).toLong
val updatedChar = (if (value == 1) char | (1 << (7 - offset % 8))
else char & ~(1 << (7 - offset % 8))).toChar

putString(key, newString.updated(offset / 8, updatedChar)).as(RespValue.Integer(resp))
}
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Simplify as suggested above.

@jdegoes
Copy link
Member

jdegoes commented Feb 15, 2022

@mvelimir Would love to get this in! Do you have a chance to push it through?

@mvelimir
Copy link
Collaborator Author

Sorry for the wait.

@mijicd mijicd merged commit 081cf75 into zio:master Feb 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support strings api in test executor
3 participants