From 68d6d79663864c256d045ef0df5dd6b6ec65222f Mon Sep 17 00:00:00 2001
From: slorello89 <42971704+slorello89@users.noreply.github.com>
Date: Mon, 18 Apr 2022 15:43:34 -0400
Subject: [PATCH 01/14] WIP
---
.../APITypes/BitfieldCommand.cs | 20 ++
.../APITypes/BitfieldOverflowHandling.cs | 33 +++
.../APITypes/BitfieldSubCommand.cs | 279 ++++++++++++++++++
.../APITypes/Signedness.cs | 28 ++
src/StackExchange.Redis/Enums/RedisCommand.cs | 2 +
.../Interfaces/IDatabase.cs | 50 ++++
.../Interfaces/IDatabaseAsync.cs | 48 +++
src/StackExchange.Redis/Message.cs | 1 +
.../PublicAPI.Unshipped.txt | 36 ++-
src/StackExchange.Redis/RedisDatabase.cs | 56 ++++
src/StackExchange.Redis/RedisLiterals.cs | 7 +
11 files changed, 559 insertions(+), 1 deletion(-)
create mode 100644 src/StackExchange.Redis/APITypes/BitfieldCommand.cs
create mode 100644 src/StackExchange.Redis/APITypes/BitfieldOverflowHandling.cs
create mode 100644 src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
create mode 100644 src/StackExchange.Redis/APITypes/Signedness.cs
diff --git a/src/StackExchange.Redis/APITypes/BitfieldCommand.cs b/src/StackExchange.Redis/APITypes/BitfieldCommand.cs
new file mode 100644
index 000000000..41755b08a
--- /dev/null
+++ b/src/StackExchange.Redis/APITypes/BitfieldCommand.cs
@@ -0,0 +1,20 @@
+namespace StackExchange.Redis;
+
+///
+/// Possible commands to use on a bitfield.
+///
+public enum BitfieldCommand
+{
+ ///
+ /// retrieves the specified integer from the bitfield.
+ ///
+ GET,
+ ///
+ /// Set's the bitfield.
+ ///
+ SET,
+ ///
+ /// Increments the bitfield.
+ ///
+ INCRBY
+}
diff --git a/src/StackExchange.Redis/APITypes/BitfieldOverflowHandling.cs b/src/StackExchange.Redis/APITypes/BitfieldOverflowHandling.cs
new file mode 100644
index 000000000..061b0e025
--- /dev/null
+++ b/src/StackExchange.Redis/APITypes/BitfieldOverflowHandling.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace StackExchange.Redis;
+
+///
+/// Defines the overflow behavior of a BITFIELD command.
+///
+public enum BitfieldOverflowHandling
+{
+ ///
+ /// Wraps around to the most negative value of signed integers, or zero for unsigned integers
+ ///
+ Wrap,
+ ///
+ /// Uses saturation arithmetic, stopping at the highest possible value for overflows, and the lowest possible value for underflows.
+ ///
+ Saturate,
+ ///
+ /// If an overflow is encountered, associated subcommand fails, and the result will be NULL.
+ ///
+ Fail
+}
+
+internal static class BitfieldOverflowHandlingExtensions
+{
+ internal static RedisValue AsRedisValue(this BitfieldOverflowHandling handling) => handling switch
+ {
+ BitfieldOverflowHandling.Fail => RedisLiterals.FAIL,
+ BitfieldOverflowHandling.Saturate => RedisLiterals.SAT,
+ BitfieldOverflowHandling.Wrap => RedisLiterals.WRAP,
+ _ => throw new ArgumentOutOfRangeException(nameof(handling))
+ };
+}
diff --git a/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs b/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
new file mode 100644
index 000000000..559f8638c
--- /dev/null
+++ b/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
@@ -0,0 +1,279 @@
+using System;
+using System.Collections.Generic;
+
+namespace StackExchange.Redis;
+
+///
+/// A subcommand for a bitfield.
+///
+public abstract class BitfieldSubCommand
+{
+ internal abstract int NumArgs { get; }
+ internal abstract void AddArgs(IList args);
+ internal virtual bool IsReadonly => false;
+ ///
+ /// The encoding of the sub-command. This might be a signed or unsigned integer.
+ ///
+ public BitfieldEncoding Encoding { get; }
+ ///
+ /// The offset into the bitfield the subcommand will traverse.
+ ///
+ public BitfieldOffset Offset { get; }
+
+ internal BitfieldSubCommand(BitfieldEncoding encoding, BitfieldOffset offset)
+ {
+ Encoding = encoding;
+ Offset = offset;
+ }
+
+ internal BitfieldSubCommand(string encoding, string offset)
+ {
+ Encoding = BitfieldEncoding.Parse(encoding);
+ Offset = BitfieldOffset.Parse(offset);
+ }
+
+}
+
+///
+/// Represents a Bitfield GET, which returns the specified bitfield.
+///
+public sealed class BitfieldGet : BitfieldSubCommand
+{
+ ///
+ /// Initializes a bitfield get subcommand
+ ///
+ /// the encoding of the subcommand.
+ /// The offset into the bitfield of the subcommand
+ public BitfieldGet(BitfieldEncoding encoding, BitfieldOffset offset) : base(encoding, offset)
+ {
+ }
+
+ ///
+ /// Initializes a bitfield get subcommand
+ ///
+ /// the encoding of the subcommand.
+ /// The offset into the bitfield of the subcommand
+ public BitfieldGet(string encoding, string offset) : base(encoding, offset)
+ {
+ }
+
+ internal override bool IsReadonly => true;
+
+ internal override int NumArgs => 3;
+
+ internal override void AddArgs(IList args)
+ {
+ args.Add(RedisLiterals.GET);
+ args.Add(Encoding.AsRedisValue);
+ args.Add(Offset.AsRedisValue);
+ }
+}
+
+///
+/// Bitfield sub-command which set's the specified range of bits to the specified value.
+///
+public sealed class BitfieldSet : BitfieldSubCommand
+{
+ ///
+ /// The value to set.
+ ///
+ public long Value { get; }
+
+ ///
+ /// Initializes a sub-command for a Bitfield Set.
+ ///
+ /// The number's encoding.
+ /// The offset into the bitfield to set.
+ /// The value to set.
+ public BitfieldSet(BitfieldEncoding encoding, BitfieldOffset offset, long value) : base(encoding, offset)
+ {
+ Value = value;
+ }
+
+ ///
+ /// Initializes a sub-command for a Bitfield Set.
+ ///
+ /// The number's encoding.
+ /// The offset into the bitfield to set.
+ /// The value to set.
+ public BitfieldSet(string encoding, string offset, long value) : base(encoding, offset)
+ {
+ Value = value;
+ }
+
+ internal override int NumArgs => 4;
+
+ internal override void AddArgs(IList args)
+ {
+ args.Add(RedisLiterals.SET);
+ args.Add(Encoding.AsRedisValue);
+ args.Add(Offset.AsRedisValue);
+ args.Add(Value);
+ }
+}
+
+///
+/// Bitfield sub-command which increments the number at the specified range of bits by the provided value
+///
+public sealed class BitfieldIncrby : BitfieldSubCommand
+{
+ ///
+ /// The value to set.
+ ///
+ public long Increment { get; }
+
+ public BitfieldOverflowHandling OverflowHandling { get; }
+
+ ///
+ /// Initializes a sub-command for a Bitfield Set.
+ ///
+ /// The number's encoding.
+ /// The offset into the bitfield to set.
+ /// The value to set.
+ /// How overflows will be handled when incrementing.
+ public BitfieldIncrby(BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap) : base(encoding, offset)
+ {
+ Increment = increment;
+ OverflowHandling = overflowHandling;
+ }
+
+ ///
+ /// Initializes a sub-command for a Bitfield Set.
+ ///
+ /// The number's encoding.
+ /// The offset into the bitfield to set.
+ /// The value to set.
+ public BitfieldIncrby(string encoding, string offset, long increment) : base(encoding, offset)
+ {
+ Increment = increment;
+ }
+
+ internal override int NumArgs => 4;
+
+ internal override void AddArgs(IList args)
+ {
+ if (OverflowHandling != BitfieldOverflowHandling.Wrap)
+ {
+ args.Add(RedisLiterals.OVERFLOW);
+ args.Add(OverflowHandling.AsRedisValue());
+ }
+ args.Add(RedisLiterals.INCRBY);
+ args.Add(Encoding.AsRedisValue);
+ args.Add(Offset.AsRedisValue);
+ args.Add(Increment);
+ }
+}
+
+
+
+///
+/// An offset into a bitfield. This is either a literal offset (number of bits from the beginning of the bitfield) or an
+/// encoding based offset, based off the encoding of the sub-command.
+///
+public readonly struct BitfieldOffset
+{
+ ///
+ /// Returns the BitfieldOffset as a RedisValue
+ ///
+ internal RedisValue AsRedisValue => $"{(ByEncoding ? "#" : string.Empty)}{Offset}";
+
+ ///
+ /// Whether or not the BitfieldOffset will work off of the sub-commands integer encoding.
+ ///
+ public bool ByEncoding { get; }
+
+ ///
+ /// The number of either bits or encoded integers to offset into the bitfield.
+ ///
+ public long Offset { get; }
+
+ ///
+ /// Initializes a bitfield offset
+ ///
+ /// Whether or not the BitfieldOffset will work off of the sub-commands integer encoding.
+ /// The number of either bits or encoded integers to offset into the bitfield.
+ public BitfieldOffset(bool byEncoding, long offset)
+ {
+ ByEncoding = byEncoding;
+ Offset = offset;
+ }
+
+ internal static BitfieldOffset Parse(string str)
+ {
+ if (str.IsNullOrEmpty())
+ {
+ throw new ArgumentException($"Cannot parse {nameof(BitfieldOffset)} from an empty or null string.", nameof(str));
+ }
+
+ long offset;
+
+ if (str[0] == '#')
+ {
+ if (long.TryParse(str.Substring(1), out offset))
+ {
+ return new BitfieldOffset(true, offset);
+ }
+ }
+ else
+ {
+ if (long.TryParse(str, out offset))
+ {
+ return new BitfieldOffset(false, offset);
+ }
+ }
+
+ throw new ArgumentException($"{str} could not be parsed into a {nameof(BitfieldOffset)}.", nameof(str));
+ }
+}
+
+///
+/// The encoding that a sub-command should use. This is either a signed or unsigned integer.
+///
+public readonly struct BitfieldEncoding
+{
+ internal RedisValue AsRedisValue => $"{Signedness.SignChar()}{Size}";
+ ///
+ /// The signedness of the integer.
+ ///
+ public Signedness Signedness { get; }
+ ///
+ /// The size of the integer.
+ ///
+ public byte Size { get; }
+
+ ///
+ /// Initializes the BitfieldEncoding.
+ ///
+ /// The encoding's
+ /// The size of the integer.
+ public BitfieldEncoding(Signedness signedness, byte size)
+ {
+ Signedness = signedness;
+ Size = size;
+ }
+
+ internal static BitfieldEncoding Parse(string str)
+ {
+ if (str.IsNullOrEmpty())
+ {
+ throw new ArgumentException($"Cannot parse {nameof(BitfieldEncoding)} from an empty or null String", nameof(str));
+ }
+
+ if (!byte.TryParse(str.Substring(1), out byte size))
+ {
+ throw new ArgumentException($"Could not parse {nameof(BitfieldEncoding)} from {str}", nameof(str));
+ }
+
+ if (char.ToLowerInvariant('i') == char.ToLowerInvariant(str[0]))
+ {
+ return new BitfieldEncoding(Signedness.Signed, size);
+ }
+
+ if (char.ToLowerInvariant('u') == char.ToLowerInvariant(str[0]))
+ {
+ return new BitfieldEncoding(Signedness.Unsigned, size);
+ }
+
+ throw new ArgumentException($"Could not parse {nameof(BitfieldEncoding)} from {str}", nameof(str));
+ }
+}
diff --git a/src/StackExchange.Redis/APITypes/Signedness.cs b/src/StackExchange.Redis/APITypes/Signedness.cs
new file mode 100644
index 000000000..d81a4a16b
--- /dev/null
+++ b/src/StackExchange.Redis/APITypes/Signedness.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace StackExchange.Redis;
+
+///
+/// Represents an integers signedness
+///
+public enum Signedness
+{
+ ///
+ /// An integer with no sign bit.
+ ///
+ Unsigned,
+ ///
+ /// An integer with a sign bit.
+ ///
+ Signed
+}
+
+internal static class SignednessExtensions
+{
+ internal static char SignChar(this Signedness sign) => sign switch
+ {
+ Signedness.Signed => 'i',
+ Signedness.Unsigned => 'u',
+ _ => throw new ArgumentOutOfRangeException(nameof(sign))
+ };
+}
diff --git a/src/StackExchange.Redis/Enums/RedisCommand.cs b/src/StackExchange.Redis/Enums/RedisCommand.cs
index f7ceb8a1b..e3022f826 100644
--- a/src/StackExchange.Redis/Enums/RedisCommand.cs
+++ b/src/StackExchange.Redis/Enums/RedisCommand.cs
@@ -11,6 +11,8 @@ internal enum RedisCommand
BGREWRITEAOF,
BGSAVE,
BITCOUNT,
+ BITFIELD,
+ BITFIELD_RO,
BITOP,
BITPOS,
BLPOP,
diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs
index 4c42fa498..183f774d3 100644
--- a/src/StackExchange.Redis/Interfaces/IDatabase.cs
+++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs
@@ -2361,6 +2361,56 @@ IEnumerable SortedSetScan(RedisKey key,
/// https://redis.io/commands/bitcount
long StringBitCount(RedisKey key, long start = 0, long end = -1, CommandFlags flags = CommandFlags.None);
+ ///
+ /// Pulls a single number out of a bitfield. Will execute a BITFIELD_RO if possible.
+ ///
+ /// The key for the string.
+ /// The encoding of the number.
+ /// The offset into the bitfield to pull the number from.
+ /// The Commands for the operation.
+ /// The number of the given at the provided .
+ /// https://redis.io/commands/bitfield
+ /// https://redis.io/commands/bitfield_ro
+ long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None);
+
+ ///
+ /// Sets a single number number in a bitfield at the provided to the provided, in the given .
+ ///
+ /// The key for the string.
+ /// The encoding of the number.
+ /// The offset into the bitfield to pull the number from.
+ /// the value to set the bitfield to.
+ /// The Commands for the operation.
+ /// The previous value as am at the provided .
+ /// https://redis.io/commands/bitfield
+ long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None);
+
+
+ ///
+ /// increments a single number number in a bitfield at the provided to the .
+ ///
+ /// The key for the string.
+ /// The encoding of the number.
+ /// The offset into the bitfield to pull the number from.
+ /// the value to increment the bitfield by.
+ /// The way integer overflows are handled.
+ /// The Commands for the operation.
+ /// The new value of the given at the provided after the incrby is applied, represented as an . Returns if the operation fails.
+ /// https://redis.io/commands/bitfield
+ long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None);
+
+
+ ///
+ /// Executes a set of Bitfield against the bitfield at the provided . Will run as a BITFIELD_RO if all operations are read-only and the command is available.
+ ///
+ /// The key of the string.
+ /// The subcommands to execute against the bitfield.
+ /// The flags for this operation.
+ /// An array of numbers corresponding to the result of each sub-command. For increment subcommands, these can be null.
+ /// https://redis.io/commands/bitfield
+ /// https://redis.io/commands/bitfield_ro
+ long?[] StringBitfield(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None);
+
///
/// Perform a bitwise operation between multiple keys (containing string values) and store the result in the destination key.
/// The BITOP command supports four bitwise operations; note that NOT is a unary operator: the second key should be omitted in this case
diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
index a54681ce5..cb777b8c7 100644
--- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
+++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
@@ -2315,6 +2315,54 @@ IAsyncEnumerable SortedSetScanAsync(RedisKey key,
/// https://redis.io/commands/bitcount
Task StringBitCountAsync(RedisKey key, long start = 0, long end = -1, CommandFlags flags = CommandFlags.None);
+ ///
+ /// Pulls a single number out of a bitfield. Will execute a BITFIELD_RO if possible.
+ ///
+ /// The key for the string.
+ /// The encoding of the number.
+ /// The offset into the bitfield to pull the number from.
+ /// The Commands for the operation.
+ /// The number of the given at the provided .
+ /// https://redis.io/commands/bitfield
+ /// https://redis.io/commands/bitfield_ro
+ Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None);
+
+ ///
+ /// Sets a single number number in a bitfield at the provided to the provided, in the given .
+ ///
+ /// The key for the string.
+ /// The encoding of the number.
+ /// The offset into the bitfield to pull the number from.
+ /// the value to set the bitfield to.
+ /// The Commands for the operation.
+ /// The previous value as am at the provided .
+ /// https://redis.io/commands/bitfield
+ Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None);
+
+ ///
+ /// increments a single number number in a bitfield at the provided to the .
+ ///
+ /// The key for the string.
+ /// The encoding of the number.
+ /// The offset into the bitfield to pull the number from.
+ /// the value to increment the bitfield by.
+ /// The way integer overflows are handled.
+ /// The Commands for the operation.
+ /// The new value of the given at the provided after the incrby is applied, represented as an . Returns if the operation fails.
+ /// https://redis.io/commands/bitfield
+ Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None);
+
+ ///
+ /// Executes a set of Bitfield against the bitfield at the provided . Will run as a BITFIELD_RO if all operations are read-only and the command is available.
+ ///
+ /// The key of the string.
+ /// The subcommands to execute against the bitfield.
+ /// The flags for this operation.
+ /// An array of numbers corresponding to the result of each sub-command. For increment subcommands, these can be null.
+ /// https://redis.io/commands/bitfield
+ /// https://redis.io/commands/bitfield_ro
+ Task StringBitfieldAsync(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None);
+
///
/// Perform a bitwise operation between multiple keys (containing string values) and store the result in the destination key.
/// The BITOP command supports four bitwise operations; note that NOT is a unary operator: the second key should be omitted in this case
diff --git a/src/StackExchange.Redis/Message.cs b/src/StackExchange.Redis/Message.cs
index 7efd5fe6c..2de10474f 100644
--- a/src/StackExchange.Redis/Message.cs
+++ b/src/StackExchange.Redis/Message.cs
@@ -330,6 +330,7 @@ public static bool IsPrimaryOnly(RedisCommand command)
{
case RedisCommand.APPEND:
case RedisCommand.BITOP:
+ case RedisCommand.BITFIELD:
case RedisCommand.BLPOP:
case RedisCommand.BRPOP:
case RedisCommand.BRPOPLPUSH:
diff --git a/src/StackExchange.Redis/PublicAPI.Unshipped.txt b/src/StackExchange.Redis/PublicAPI.Unshipped.txt
index 5f282702b..981a4c756 100644
--- a/src/StackExchange.Redis/PublicAPI.Unshipped.txt
+++ b/src/StackExchange.Redis/PublicAPI.Unshipped.txt
@@ -1 +1,35 @@
-
\ No newline at end of file
+StackExchange.Redis.BitfieldEncoding
+StackExchange.Redis.BitfieldEncoding.BitfieldEncoding() -> void
+StackExchange.Redis.BitfieldEncoding.BitfieldEncoding(StackExchange.Redis.Signedness signedness, byte size) -> void
+StackExchange.Redis.BitfieldEncoding.Signedness.get -> StackExchange.Redis.Signedness
+StackExchange.Redis.BitfieldEncoding.Size.get -> byte
+StackExchange.Redis.BitfieldGet
+StackExchange.Redis.BitfieldGet.BitfieldGet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset) -> void
+StackExchange.Redis.BitfieldGet.BitfieldGet(string! encoding, string! offset) -> void
+StackExchange.Redis.BitfieldIncrby
+StackExchange.Redis.BitfieldIncrby.BitfieldIncrby(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment) -> void
+StackExchange.Redis.BitfieldIncrby.BitfieldIncrby(string! encoding, string! offset, long increment) -> void
+StackExchange.Redis.BitfieldIncrby.Increment.get -> long
+StackExchange.Redis.BitfieldOffset
+StackExchange.Redis.BitfieldOffset.BitfieldOffset() -> void
+StackExchange.Redis.BitfieldOffset.BitfieldOffset(bool byEncoding, long offset) -> void
+StackExchange.Redis.BitfieldOffset.ByEncoding.get -> bool
+StackExchange.Redis.BitfieldOffset.Offset.get -> long
+StackExchange.Redis.BitfieldSet
+StackExchange.Redis.BitfieldSet.BitfieldSet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value) -> void
+StackExchange.Redis.BitfieldSet.BitfieldSet(string! encoding, string! offset, long value) -> void
+StackExchange.Redis.BitfieldSet.Value.get -> long
+StackExchange.Redis.BitfieldSubCommand
+StackExchange.Redis.BitfieldSubCommand.Encoding.get -> StackExchange.Redis.BitfieldEncoding
+StackExchange.Redis.BitfieldSubCommand.Offset.get -> StackExchange.Redis.BitfieldOffset
+StackExchange.Redis.IDatabase.StringBitfield(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldSubCommand![]! subcommands, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?[]!
+StackExchange.Redis.IDatabase.StringBitfieldGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
+StackExchange.Redis.IDatabase.StringBitfieldIncrement(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?
+StackExchange.Redis.IDatabase.StringBitfieldSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
+StackExchange.Redis.IDatabaseAsync.StringBitfieldAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldSubCommand![]! subcommands, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
+StackExchange.Redis.IDatabaseAsync.StringBitfieldGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
+StackExchange.Redis.IDatabaseAsync.StringBitfieldIncrementAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
+StackExchange.Redis.IDatabaseAsync.StringBitfieldSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
+StackExchange.Redis.Signedness
+StackExchange.Redis.Signedness.Signed = 1 -> StackExchange.Redis.Signedness
+StackExchange.Redis.Signedness.Unsigned = 0 -> StackExchange.Redis.Signedness
\ No newline at end of file
diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs
index 500fcc963..9a76b0854 100644
--- a/src/StackExchange.Redis/RedisDatabase.cs
+++ b/src/StackExchange.Redis/RedisDatabase.cs
@@ -1,6 +1,7 @@
using System;
using System.Buffers;
using System.Collections.Generic;
+using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
@@ -2721,12 +2722,40 @@ public long StringBitCount(RedisKey key, long start = 0, long end = -1, CommandF
return ExecuteSync(msg, ResultProcessor.Int64);
}
+ public long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset,
+ CommandFlags flags = CommandFlags.None) =>
+ throw new NotImplementedException();
+
+ public long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value,
+ CommandFlags flags = CommandFlags.None) =>
+ throw new NotImplementedException();
+
+ public long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment,
+ BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None) =>
+ throw new NotImplementedException();
+
+ public long?[] StringBitfield(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None) => throw new NotImplementedException();
+
public Task StringBitCountAsync(RedisKey key, long start = 0, long end = -1, CommandFlags flags = CommandFlags.None)
{
var msg = Message.Create(Database, flags, RedisCommand.BITCOUNT, key, start, end);
return ExecuteAsync(msg, ResultProcessor.Int64);
}
+ public Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset,
+ CommandFlags flags = CommandFlags.None) =>
+ throw new NotImplementedException();
+
+ public Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value,
+ CommandFlags flags = CommandFlags.None) =>
+ throw new NotImplementedException();
+
+ public Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment,
+ BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None) =>
+ throw new NotImplementedException();
+
+ public Task StringBitfieldAsync(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None) => throw new NotImplementedException();
+
public long StringBitOperation(Bitwise operation, RedisKey destination, RedisKey first, RedisKey second, CommandFlags flags = CommandFlags.None)
{
var msg = GetStringBitOperationMessage(operation, destination, first, second, flags);
@@ -3057,6 +3086,33 @@ public Task StringSetRangeAsync(RedisKey key, long offset, RedisValu
_ => throw new ArgumentException("Expiry time must be either Utc or Local", nameof(when)),
};
+ private Message GetBitfieldMessage(in RedisKey key, BitfieldSubCommand subcommand, CommandFlags flags)
+ {
+ var args = new List(subcommand.NumArgs);
+ subcommand.AddArgs(args);
+ RedisCommand command = RedisCommand.BITFIELD;
+ if (subcommand is BitfieldGet && multiplexer.GetServer(multiplexer.EndPoints[0]).Version >= RedisFeatures.v6_2_0)
+ {
+ command = RedisCommand.BITFIELD_RO;
+ }
+
+ return Message.Create(Database, flags, command, key, args.ToArray());
+ }
+
+ private Message GetBitfieldMessage(in RedisKey key, BitfieldSubCommand[] subCommands, CommandFlags flags)
+ {
+ var args = new List(subCommands.Sum(sc => sc.NumArgs));
+ var canBeReadonly = subCommands.All(sc => sc.IsReadonly);
+ var command = canBeReadonly && multiplexer.GetServer(multiplexer.EndPoints[0]).Version >= RedisFeatures.v6_2_0 ? RedisCommand.BITFIELD_RO : RedisCommand.BITFIELD;
+
+ foreach (var subcommand in subCommands)
+ {
+ subcommand.AddArgs(args);
+ }
+
+ return Message.Create(Database, flags, command, key, args.ToArray());
+ }
+
private Message GetCopyMessage(in RedisKey sourceKey, RedisKey destinationKey, int destinationDatabase, bool replace, CommandFlags flags) =>
destinationDatabase switch
{
diff --git a/src/StackExchange.Redis/RedisLiterals.cs b/src/StackExchange.Redis/RedisLiterals.cs
index 3b405ae8b..3dfa62e3c 100644
--- a/src/StackExchange.Redis/RedisLiterals.cs
+++ b/src/StackExchange.Redis/RedisLiterals.cs
@@ -69,6 +69,7 @@ public static readonly RedisValue
HISTORY = "HISTORY",
ID = "ID",
IDLETIME = "IDLETIME",
+ INCRBY = "INCRBY",
KEEPTTL = "KEEPTTL",
KILL = "KILL",
LATEST = "LATEST",
@@ -90,6 +91,7 @@ public static readonly RedisValue
NX = "NX",
OBJECT = "OBJECT",
OR = "OR",
+ OVERFLOW = "OVERFLOW",
PAUSE = "PAUSE",
PERSIST = "PERSIST",
PING = "PING",
@@ -161,6 +163,11 @@ public static readonly RedisValue
m = "m",
mi = "mi",
+ //Bitfield literals
+ FAIL = "FAIL",
+ SAT = "SAT",
+ WRAP = "WRAP",
+
// misc (config, etc)
databases = "databases",
master = "master",
From 1695639f351079ed804219a9eb5dd8c22a329dc8 Mon Sep 17 00:00:00 2001
From: slorello89 <42971704+slorello89@users.noreply.github.com>
Date: Tue, 19 Apr 2022 09:51:47 -0400
Subject: [PATCH 02/14] Bitfield feature
---
.../APITypes/BitfieldCommand.cs | 20 ---
.../APITypes/BitfieldSubCommand.cs | 3 +
.../KeyspaceIsolation/DatabaseWrapper.cs | 12 ++
.../KeyspaceIsolation/WrapperBase.cs | 13 ++
src/StackExchange.Redis/PublicAPI.Shipped.txt | 40 ++++++
.../PublicAPI.Unshipped.txt | 36 +----
src/StackExchange.Redis/RawResult.cs | 3 +
src/StackExchange.Redis/RedisDatabase.cs | 60 ++++++---
src/StackExchange.Redis/ResultProcessor.cs | 41 ++++++
tests/StackExchange.Redis.Tests/Bitfield.cs | 123 ++++++++++++++++++
10 files changed, 276 insertions(+), 75 deletions(-)
delete mode 100644 src/StackExchange.Redis/APITypes/BitfieldCommand.cs
create mode 100644 tests/StackExchange.Redis.Tests/Bitfield.cs
diff --git a/src/StackExchange.Redis/APITypes/BitfieldCommand.cs b/src/StackExchange.Redis/APITypes/BitfieldCommand.cs
deleted file mode 100644
index 41755b08a..000000000
--- a/src/StackExchange.Redis/APITypes/BitfieldCommand.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace StackExchange.Redis;
-
-///
-/// Possible commands to use on a bitfield.
-///
-public enum BitfieldCommand
-{
- ///
- /// retrieves the specified integer from the bitfield.
- ///
- GET,
- ///
- /// Set's the bitfield.
- ///
- SET,
- ///
- /// Increments the bitfield.
- ///
- INCRBY
-}
diff --git a/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs b/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
index 559f8638c..f31b5d96a 100644
--- a/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
+++ b/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
@@ -122,6 +122,9 @@ public sealed class BitfieldIncrby : BitfieldSubCommand
///
public long Increment { get; }
+ ///
+ /// Determines how overflows are handled for the bitfield.
+ ///
public BitfieldOverflowHandling OverflowHandling { get; }
///
diff --git a/src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs b/src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs
index 7def559b2..ac0fec907 100644
--- a/src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs
+++ b/src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs
@@ -568,6 +568,18 @@ public long StringAppend(RedisKey key, RedisValue value, CommandFlags flags = Co
public long StringBitCount(RedisKey key, long start = 0, long end = -1, CommandFlags flags = CommandFlags.None) =>
Inner.StringBitCount(ToInner(key), start, end, flags);
+ public long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldGet(ToInner(key), encoding, offset, flags);
+
+ public long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldSet(ToInner(key), encoding, offset, value, flags);
+
+ public long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldIncrement(ToInner(key), encoding, offset, increment, overflowHandling, flags);
+
+ public long?[] StringBitfield(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfield(key, subcommands, flags);
+
public long StringBitOperation(Bitwise operation, RedisKey destination, RedisKey[] keys, CommandFlags flags = CommandFlags.None) =>
Inner.StringBitOperation(operation, ToInner(destination), ToInner(keys), flags);
diff --git a/src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs b/src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs
index 5a1437e33..bea205502 100644
--- a/src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs
+++ b/src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs
@@ -585,6 +585,19 @@ public Task StringAppendAsync(RedisKey key, RedisValue value, CommandFlags
public Task StringBitCountAsync(RedisKey key, long start = 0, long end = -1, CommandFlags flags = CommandFlags.None) =>
Inner.StringBitCountAsync(ToInner(key), start, end, flags);
+ public Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset,
+ CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldGetAsync(ToInner(key), encoding, offset, flags);
+
+ public Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldSetAsync(ToInner(key), encoding, offset, value, flags);
+
+ public Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldIncrementAsync(ToInner(key), encoding, offset, increment, overflowHandling, flags);
+
+ public Task StringBitfieldAsync(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldAsync(ToInner(key), subcommands, flags);
+
public Task StringBitOperationAsync(Bitwise operation, RedisKey destination, RedisKey[] keys, CommandFlags flags = CommandFlags.None) =>
Inner.StringBitOperationAsync(operation, ToInner(destination), ToInner(keys), flags);
diff --git a/src/StackExchange.Redis/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI.Shipped.txt
index 7b4dfb2df..8739d2d16 100644
--- a/src/StackExchange.Redis/PublicAPI.Shipped.txt
+++ b/src/StackExchange.Redis/PublicAPI.Shipped.txt
@@ -66,6 +66,35 @@ StackExchange.Redis.BacklogPolicy.AbortPendingOnConnectionFailure.init -> void
StackExchange.Redis.BacklogPolicy.BacklogPolicy() -> void
StackExchange.Redis.BacklogPolicy.QueueWhileDisconnected.get -> bool
StackExchange.Redis.BacklogPolicy.QueueWhileDisconnected.init -> void
+StackExchange.Redis.BitfieldEncoding
+StackExchange.Redis.BitfieldEncoding.BitfieldEncoding() -> void
+StackExchange.Redis.BitfieldEncoding.BitfieldEncoding(StackExchange.Redis.Signedness signedness, byte size) -> void
+StackExchange.Redis.BitfieldEncoding.Signedness.get -> StackExchange.Redis.Signedness
+StackExchange.Redis.BitfieldEncoding.Size.get -> byte
+StackExchange.Redis.BitfieldGet
+StackExchange.Redis.BitfieldGet.BitfieldGet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset) -> void
+StackExchange.Redis.BitfieldGet.BitfieldGet(string! encoding, string! offset) -> void
+StackExchange.Redis.BitfieldIncrby
+StackExchange.Redis.BitfieldIncrby.BitfieldIncrby(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap) -> void
+StackExchange.Redis.BitfieldIncrby.BitfieldIncrby(string! encoding, string! offset, long increment) -> void
+StackExchange.Redis.BitfieldIncrby.Increment.get -> long
+StackExchange.Redis.BitfieldIncrby.OverflowHandling.get -> StackExchange.Redis.BitfieldOverflowHandling
+StackExchange.Redis.BitfieldOffset
+StackExchange.Redis.BitfieldOffset.BitfieldOffset() -> void
+StackExchange.Redis.BitfieldOffset.BitfieldOffset(bool byEncoding, long offset) -> void
+StackExchange.Redis.BitfieldOffset.ByEncoding.get -> bool
+StackExchange.Redis.BitfieldOffset.Offset.get -> long
+StackExchange.Redis.BitfieldOverflowHandling
+StackExchange.Redis.BitfieldOverflowHandling.Fail = 2 -> StackExchange.Redis.BitfieldOverflowHandling
+StackExchange.Redis.BitfieldOverflowHandling.Saturate = 1 -> StackExchange.Redis.BitfieldOverflowHandling
+StackExchange.Redis.BitfieldOverflowHandling.Wrap = 0 -> StackExchange.Redis.BitfieldOverflowHandling
+StackExchange.Redis.BitfieldSet
+StackExchange.Redis.BitfieldSet.BitfieldSet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value) -> void
+StackExchange.Redis.BitfieldSet.BitfieldSet(string! encoding, string! offset, long value) -> void
+StackExchange.Redis.BitfieldSet.Value.get -> long
+StackExchange.Redis.BitfieldSubCommand
+StackExchange.Redis.BitfieldSubCommand.Encoding.get -> StackExchange.Redis.BitfieldEncoding
+StackExchange.Redis.BitfieldSubCommand.Offset.get -> StackExchange.Redis.BitfieldOffset
StackExchange.Redis.Bitwise
StackExchange.Redis.Bitwise.And = 0 -> StackExchange.Redis.Bitwise
StackExchange.Redis.Bitwise.Not = 3 -> StackExchange.Redis.Bitwise
@@ -681,6 +710,10 @@ StackExchange.Redis.IDatabase.StringBitCount(StackExchange.Redis.RedisKey key, l
StackExchange.Redis.IDatabase.StringBitOperation(StackExchange.Redis.Bitwise operation, StackExchange.Redis.RedisKey destination, StackExchange.Redis.RedisKey first, StackExchange.Redis.RedisKey second = default(StackExchange.Redis.RedisKey), StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.IDatabase.StringBitOperation(StackExchange.Redis.Bitwise operation, StackExchange.Redis.RedisKey destination, StackExchange.Redis.RedisKey[]! keys, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.IDatabase.StringBitPosition(StackExchange.Redis.RedisKey key, bool bit, long start = 0, long end = -1, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
+StackExchange.Redis.IDatabase.StringBitfield(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldSubCommand![]! subcommands, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?[]!
+StackExchange.Redis.IDatabase.StringBitfieldGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
+StackExchange.Redis.IDatabase.StringBitfieldIncrement(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?
+StackExchange.Redis.IDatabase.StringBitfieldSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.IDatabase.StringDecrement(StackExchange.Redis.RedisKey key, double value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> double
StackExchange.Redis.IDatabase.StringDecrement(StackExchange.Redis.RedisKey key, long value = 1, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.IDatabase.StringGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue
@@ -889,6 +922,10 @@ StackExchange.Redis.IDatabaseAsync.StreamReadGroupAsync(StackExchange.Redis.Stre
StackExchange.Redis.IDatabaseAsync.StreamTrimAsync(StackExchange.Redis.RedisKey key, int maxLength, bool useApproximateMaxLength = false, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringAppendAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitCountAsync(StackExchange.Redis.RedisKey key, long start = 0, long end = -1, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
+StackExchange.Redis.IDatabaseAsync.StringBitfieldAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldSubCommand![]! subcommands, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
+StackExchange.Redis.IDatabaseAsync.StringBitfieldGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
+StackExchange.Redis.IDatabaseAsync.StringBitfieldIncrementAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
+StackExchange.Redis.IDatabaseAsync.StringBitfieldSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitOperationAsync(StackExchange.Redis.Bitwise operation, StackExchange.Redis.RedisKey destination, StackExchange.Redis.RedisKey first, StackExchange.Redis.RedisKey second = default(StackExchange.Redis.RedisKey), StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitOperationAsync(StackExchange.Redis.Bitwise operation, StackExchange.Redis.RedisKey destination, StackExchange.Redis.RedisKey[]! keys, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitPositionAsync(StackExchange.Redis.RedisKey key, bool bit, long start = 0, long end = -1, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
@@ -1354,6 +1391,9 @@ StackExchange.Redis.ShutdownMode
StackExchange.Redis.ShutdownMode.Always = 2 -> StackExchange.Redis.ShutdownMode
StackExchange.Redis.ShutdownMode.Default = 0 -> StackExchange.Redis.ShutdownMode
StackExchange.Redis.ShutdownMode.Never = 1 -> StackExchange.Redis.ShutdownMode
+StackExchange.Redis.Signedness
+StackExchange.Redis.Signedness.Signed = 1 -> StackExchange.Redis.Signedness
+StackExchange.Redis.Signedness.Unsigned = 0 -> StackExchange.Redis.Signedness
StackExchange.Redis.SlotRange
StackExchange.Redis.SlotRange.CompareTo(StackExchange.Redis.SlotRange other) -> int
StackExchange.Redis.SlotRange.Equals(StackExchange.Redis.SlotRange other) -> bool
diff --git a/src/StackExchange.Redis/PublicAPI.Unshipped.txt b/src/StackExchange.Redis/PublicAPI.Unshipped.txt
index 981a4c756..5f282702b 100644
--- a/src/StackExchange.Redis/PublicAPI.Unshipped.txt
+++ b/src/StackExchange.Redis/PublicAPI.Unshipped.txt
@@ -1,35 +1 @@
-StackExchange.Redis.BitfieldEncoding
-StackExchange.Redis.BitfieldEncoding.BitfieldEncoding() -> void
-StackExchange.Redis.BitfieldEncoding.BitfieldEncoding(StackExchange.Redis.Signedness signedness, byte size) -> void
-StackExchange.Redis.BitfieldEncoding.Signedness.get -> StackExchange.Redis.Signedness
-StackExchange.Redis.BitfieldEncoding.Size.get -> byte
-StackExchange.Redis.BitfieldGet
-StackExchange.Redis.BitfieldGet.BitfieldGet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset) -> void
-StackExchange.Redis.BitfieldGet.BitfieldGet(string! encoding, string! offset) -> void
-StackExchange.Redis.BitfieldIncrby
-StackExchange.Redis.BitfieldIncrby.BitfieldIncrby(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment) -> void
-StackExchange.Redis.BitfieldIncrby.BitfieldIncrby(string! encoding, string! offset, long increment) -> void
-StackExchange.Redis.BitfieldIncrby.Increment.get -> long
-StackExchange.Redis.BitfieldOffset
-StackExchange.Redis.BitfieldOffset.BitfieldOffset() -> void
-StackExchange.Redis.BitfieldOffset.BitfieldOffset(bool byEncoding, long offset) -> void
-StackExchange.Redis.BitfieldOffset.ByEncoding.get -> bool
-StackExchange.Redis.BitfieldOffset.Offset.get -> long
-StackExchange.Redis.BitfieldSet
-StackExchange.Redis.BitfieldSet.BitfieldSet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value) -> void
-StackExchange.Redis.BitfieldSet.BitfieldSet(string! encoding, string! offset, long value) -> void
-StackExchange.Redis.BitfieldSet.Value.get -> long
-StackExchange.Redis.BitfieldSubCommand
-StackExchange.Redis.BitfieldSubCommand.Encoding.get -> StackExchange.Redis.BitfieldEncoding
-StackExchange.Redis.BitfieldSubCommand.Offset.get -> StackExchange.Redis.BitfieldOffset
-StackExchange.Redis.IDatabase.StringBitfield(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldSubCommand![]! subcommands, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?[]!
-StackExchange.Redis.IDatabase.StringBitfieldGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
-StackExchange.Redis.IDatabase.StringBitfieldIncrement(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?
-StackExchange.Redis.IDatabase.StringBitfieldSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
-StackExchange.Redis.IDatabaseAsync.StringBitfieldAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldSubCommand![]! subcommands, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
-StackExchange.Redis.IDatabaseAsync.StringBitfieldGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
-StackExchange.Redis.IDatabaseAsync.StringBitfieldIncrementAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
-StackExchange.Redis.IDatabaseAsync.StringBitfieldSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
-StackExchange.Redis.Signedness
-StackExchange.Redis.Signedness.Signed = 1 -> StackExchange.Redis.Signedness
-StackExchange.Redis.Signedness.Unsigned = 0 -> StackExchange.Redis.Signedness
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/StackExchange.Redis/RawResult.cs b/src/StackExchange.Redis/RawResult.cs
index 919054411..592eccf48 100644
--- a/src/StackExchange.Redis/RawResult.cs
+++ b/src/StackExchange.Redis/RawResult.cs
@@ -256,6 +256,9 @@ internal bool GetBoolean()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal double?[]? GetItemsAsDoubles() => this.ToArray((in RawResult x) => x.TryGetDouble(out double val) ? val : null);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal long?[]? GetItemsAsInt64s() => this.ToArray((in RawResult x) => x.TryGetInt64(out long val) ? val : null);
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal RedisKey[]? GetItemsAsKeys() => this.ToArray((in RawResult x) => x.AsRedisKey());
diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs
index 9a76b0854..fe7601cfc 100644
--- a/src/StackExchange.Redis/RedisDatabase.cs
+++ b/src/StackExchange.Redis/RedisDatabase.cs
@@ -2722,19 +2722,29 @@ public long StringBitCount(RedisKey key, long start = 0, long end = -1, CommandF
return ExecuteSync(msg, ResultProcessor.Int64);
}
- public long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset,
- CommandFlags flags = CommandFlags.None) =>
- throw new NotImplementedException();
+ public long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None)
+ {
+ var msg = GetBitfieldMessage(key, new BitfieldGet(encoding, offset), flags);
+ return ExecuteSync(msg, ResultProcessor.Int64);
+ }
- public long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value,
- CommandFlags flags = CommandFlags.None) =>
- throw new NotImplementedException();
+ public long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None)
+ {
+ var msg = GetBitfieldMessage(key, new BitfieldSet(encoding, offset, value), flags);
+ return ExecuteSync(msg, ResultProcessor.Int64);
+ }
- public long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment,
- BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None) =>
- throw new NotImplementedException();
+ public long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None)
+ {
+ var msg = GetBitfieldMessage(key, new BitfieldIncrby(encoding, offset, increment, overflowHandling), flags);
+ return ExecuteSync(msg, ResultProcessor.NullableInt64);
+ }
- public long?[] StringBitfield(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None) => throw new NotImplementedException();
+ public long?[] StringBitfield(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None)
+ {
+ var msg = GetBitfieldMessage(key, subcommands, flags);
+ return ExecuteSync(msg, ResultProcessor.NullableInt64Array, defaultValue: Array.Empty());
+ }
public Task StringBitCountAsync(RedisKey key, long start = 0, long end = -1, CommandFlags flags = CommandFlags.None)
{
@@ -2742,19 +2752,29 @@ public Task StringBitCountAsync(RedisKey key, long start = 0, long end = -
return ExecuteAsync(msg, ResultProcessor.Int64);
}
- public Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset,
- CommandFlags flags = CommandFlags.None) =>
- throw new NotImplementedException();
+ public Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None)
+ {
+ var msg = GetBitfieldMessage(key, new BitfieldGet(encoding, offset), flags);
+ return ExecuteAsync(msg, ResultProcessor.Int64);
+ }
- public Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value,
- CommandFlags flags = CommandFlags.None) =>
- throw new NotImplementedException();
+ public Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None)
+ {
+ var msg = GetBitfieldMessage(key, new BitfieldSet(encoding, offset, value), flags);
+ return ExecuteAsync(msg, ResultProcessor.Int64);
+ }
- public Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment,
- BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None) =>
- throw new NotImplementedException();
+ public Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None)
+ {
+ var msg = GetBitfieldMessage(key, new BitfieldIncrby(encoding, offset, increment, overflowHandling), flags);
+ return ExecuteAsync(msg, ResultProcessor.NullableInt64);
+ }
- public Task StringBitfieldAsync(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None) => throw new NotImplementedException();
+ public Task StringBitfieldAsync(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None)
+ {
+ var msg = GetBitfieldMessage(key, subcommands, flags);
+ return ExecuteAsync(msg, ResultProcessor.NullableInt64Array, defaultValue: Array.Empty());
+ }
public long StringBitOperation(Bitwise operation, RedisKey destination, RedisKey first, RedisKey second, CommandFlags flags = CommandFlags.None)
{
diff --git a/src/StackExchange.Redis/ResultProcessor.cs b/src/StackExchange.Redis/ResultProcessor.cs
index fedaa1982..219574a5d 100644
--- a/src/StackExchange.Redis/ResultProcessor.cs
+++ b/src/StackExchange.Redis/ResultProcessor.cs
@@ -64,6 +64,9 @@ public static readonly ResultProcessor
public static readonly ResultProcessor
NullableDoubleArray = new NullableDoubleArrayProcessor();
+ public static readonly ResultProcessor
+ NullableInt64Array = new NullableInt64ArrayProcessor();
+
public static readonly ResultProcessor
NullableInt64 = new NullableInt64Processor();
@@ -1125,6 +1128,14 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
SetResult(message, i64);
return true;
}
+ break;
+ case ResultType.MultiBulk:
+ if (result.GetItems()[0].TryGetInt64(out i64))
+ {
+ SetResult(message, i64);
+ return true;
+ }
+
break;
}
return false;
@@ -1148,6 +1159,21 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
}
}
+
+ private sealed class NullableInt64ArrayProcessor : ResultProcessor
+ {
+ protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result)
+ {
+ if (result.Type == ResultType.MultiBulk && !result.IsNull)
+ {
+ var arr = result.GetItemsAsInt64s()!;
+ SetResult(message, arr);
+ return true;
+ }
+ return false;
+ }
+ }
+
private sealed class NullableDoubleArrayProcessor : ResultProcessor
{
protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result)
@@ -1208,6 +1234,21 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
SetResult(message, i64);
return true;
}
+ break;
+ case ResultType.MultiBulk:
+ var item = result.GetItems()[0];
+ if (item.IsNull)
+ {
+ SetResult(message, null);
+ return true;
+ }
+
+ if (item.TryGetInt64(out i64))
+ {
+ SetResult(message, i64);
+ return true;
+ }
+
break;
}
return false;
diff --git a/tests/StackExchange.Redis.Tests/Bitfield.cs b/tests/StackExchange.Redis.Tests/Bitfield.cs
new file mode 100644
index 000000000..0f52a191c
--- /dev/null
+++ b/tests/StackExchange.Redis.Tests/Bitfield.cs
@@ -0,0 +1,123 @@
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace StackExchange.Redis.Tests;
+
+[Collection(SharedConnectionFixture.Key)]
+public class Bitfield : TestBase
+{
+ public Bitfield(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { }
+
+ [Fact]
+ public void TestBitfieldHappyPath()
+ {
+
+ using var conn = Create(require: RedisFeatures.v3_2_0);
+ var db = conn.GetDatabase();
+ RedisKey key = Me();
+ db.KeyDelete(key);
+
+ var encoding = new BitfieldEncoding(Signedness.Signed, 10);
+ var offset = new BitfieldOffset(true, 1);
+
+ // should be the old value
+ var setResult = db.StringBitfieldSet(key, encoding, offset, -255);
+ var getResult = db.StringBitfieldGet(key, encoding, offset);
+ var incrementResult = db.StringBitfieldIncrement(key, encoding, offset, -10);
+ Assert.Equal(0, setResult);
+ Assert.Equal(-255, getResult);
+ Assert.Equal(-265, incrementResult);
+
+ encoding = new BitfieldEncoding(Signedness.Unsigned, 18);
+ offset = new BitfieldOffset(false, 22);
+
+ setResult = db.StringBitfieldSet(key, encoding, offset, 262123);
+ getResult = db.StringBitfieldGet(key, encoding, offset);
+ incrementResult = db.StringBitfieldIncrement(key, encoding, offset, 20);
+
+ Assert.Equal(0, setResult);
+ Assert.Equal(262123, getResult);
+ Assert.Equal(262143, incrementResult);
+ }
+
+ [Fact]
+ public async Task TestBitfieldHappyPathAsync()
+ {
+
+ using var conn = Create(require: RedisFeatures.v3_2_0);
+ var db = conn.GetDatabase();
+ RedisKey key = Me();
+ db.KeyDelete(key);
+
+ var encoding = new BitfieldEncoding(Signedness.Signed, 10);
+ var offset = new BitfieldOffset(true, 1);
+
+ // should be the old value
+ var setResult = await db.StringBitfieldSetAsync(key, encoding, offset, -255);
+ var getResult = await db.StringBitfieldGetAsync(key, encoding, offset);
+ var incrementResult = await db.StringBitfieldIncrementAsync(key, encoding, offset, -10);
+ Assert.Equal(0, setResult);
+ Assert.Equal(-255, getResult);
+ Assert.Equal(-265, incrementResult);
+
+ encoding = new BitfieldEncoding(Signedness.Unsigned, 18);
+ offset = new BitfieldOffset(false, 22);
+
+ setResult = await db.StringBitfieldSetAsync(key, encoding, offset, 262123);
+ getResult = await db.StringBitfieldGetAsync(key, encoding, offset);
+ incrementResult = await db.StringBitfieldIncrementAsync(key, encoding, offset, 20);
+
+ Assert.Equal(0, setResult);
+ Assert.Equal(262123, getResult);
+ Assert.Equal(262143, incrementResult);
+ }
+
+ [Fact]
+ public async Task TestBitfieldMulti()
+ {
+ using var conn = Create(require: RedisFeatures.v3_2_0);
+ var db = conn.GetDatabase();
+ RedisKey key = Me();
+ db.KeyDelete(key);
+
+ var set1 = new BitfieldSet(new BitfieldEncoding(Signedness.Unsigned, 3), new BitfieldOffset(false, 5), 7);
+ var get1 = new BitfieldGet(new BitfieldEncoding(Signedness.Unsigned, 3), new BitfieldOffset(false, 5));
+ var incr1 = new BitfieldIncrby(new BitfieldEncoding(Signedness.Unsigned, 3), new BitfieldOffset(false, 5), -1);
+
+ var set2 = new BitfieldSet(new BitfieldEncoding(Signedness.Signed, 45), new BitfieldOffset(true, 1), 17592186044415);
+ var get2 = new BitfieldGet(new BitfieldEncoding(Signedness.Signed, 45), new BitfieldOffset(true, 1));
+ var incr2 = new BitfieldIncrby(new BitfieldEncoding(Signedness.Signed, 45), new BitfieldOffset(true, 1), 1, BitfieldOverflowHandling.Fail);
+
+ var subcommands = new BitfieldSubCommand[] {set1, get1, incr1, set2, get2, incr2};
+ var res = await db.StringBitfieldAsync(key, subcommands);
+
+ Assert.Equal(0, res[0]);
+ Assert.Equal(7, res[1]);
+ Assert.Equal(6, res[2]);
+ Assert.Equal(0, res[3]);
+ Assert.Equal(17592186044415, res[4]);
+ Assert.Null(res[5]);
+ }
+
+ [Fact]
+ public async Task TestOverflows()
+ {
+ using var conn = Create(require: RedisFeatures.v3_2_0);
+ var db = conn.GetDatabase();
+ RedisKey key = Me();
+ db.KeyDelete(key);
+
+ var encoding = new BitfieldEncoding(Signedness.Signed, 3);
+ var offset = new BitfieldOffset(true, 3);
+
+ await db.StringBitfieldSetAsync(key, encoding, offset, 3);
+ var incrFail = await db.StringBitfieldIncrementAsync(key, encoding, offset, 1, BitfieldOverflowHandling.Fail);
+ Assert.Null(incrFail);
+ var incrWrap = await db.StringBitfieldIncrementAsync(key, encoding, offset, 1);
+ Assert.Equal(-4, incrWrap);
+ await db.StringBitfieldSetAsync(key, encoding, offset, 3);
+ var incrSat = await db.StringBitfieldIncrementAsync(key, encoding, offset, 1, BitfieldOverflowHandling.Saturate);
+ Assert.Equal(3, incrSat);
+ }
+}
From 566071322c272a2e279214238fabe89ab7c46433 Mon Sep 17 00:00:00 2001
From: slorello89 <42971704+slorello89@users.noreply.github.com>
Date: Tue, 19 Apr 2022 09:54:37 -0400
Subject: [PATCH 03/14] accurate reporting of num args for incr
---
src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs b/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
index f31b5d96a..45dbe6993 100644
--- a/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
+++ b/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
@@ -151,7 +151,7 @@ public BitfieldIncrby(string encoding, string offset, long increment) : base(enc
Increment = increment;
}
- internal override int NumArgs => 4;
+ internal override int NumArgs => OverflowHandling == BitfieldOverflowHandling.Wrap ? 4 : 6;
internal override void AddArgs(IList args)
{
From bdb9128ed505d8b690354a3170ff0a2540f2f652 Mon Sep 17 00:00:00 2001
From: slorello89 <42971704+slorello89@users.noreply.github.com>
Date: Tue, 19 Apr 2022 09:57:38 -0400
Subject: [PATCH 04/14] removing unused parsing methods
---
.../APITypes/BitfieldSubCommand.cs | 89 -------------------
src/StackExchange.Redis/PublicAPI.Shipped.txt | 3 -
2 files changed, 92 deletions(-)
diff --git a/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs b/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
index 45dbe6993..029be1f2c 100644
--- a/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
+++ b/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
@@ -26,12 +26,6 @@ internal BitfieldSubCommand(BitfieldEncoding encoding, BitfieldOffset offset)
Offset = offset;
}
- internal BitfieldSubCommand(string encoding, string offset)
- {
- Encoding = BitfieldEncoding.Parse(encoding);
- Offset = BitfieldOffset.Parse(offset);
- }
-
}
///
@@ -48,15 +42,6 @@ public BitfieldGet(BitfieldEncoding encoding, BitfieldOffset offset) : base(enco
{
}
- ///
- /// Initializes a bitfield get subcommand
- ///
- /// the encoding of the subcommand.
- /// The offset into the bitfield of the subcommand
- public BitfieldGet(string encoding, string offset) : base(encoding, offset)
- {
- }
-
internal override bool IsReadonly => true;
internal override int NumArgs => 3;
@@ -90,17 +75,6 @@ public BitfieldSet(BitfieldEncoding encoding, BitfieldOffset offset, long value)
Value = value;
}
- ///
- /// Initializes a sub-command for a Bitfield Set.
- ///
- /// The number's encoding.
- /// The offset into the bitfield to set.
- /// The value to set.
- public BitfieldSet(string encoding, string offset, long value) : base(encoding, offset)
- {
- Value = value;
- }
-
internal override int NumArgs => 4;
internal override void AddArgs(IList args)
@@ -140,17 +114,6 @@ public BitfieldIncrby(BitfieldEncoding encoding, BitfieldOffset offset, long inc
OverflowHandling = overflowHandling;
}
- ///
- /// Initializes a sub-command for a Bitfield Set.
- ///
- /// The number's encoding.
- /// The offset into the bitfield to set.
- /// The value to set.
- public BitfieldIncrby(string encoding, string offset, long increment) : base(encoding, offset)
- {
- Increment = increment;
- }
-
internal override int NumArgs => OverflowHandling == BitfieldOverflowHandling.Wrap ? 4 : 6;
internal override void AddArgs(IList args)
@@ -200,33 +163,6 @@ public BitfieldOffset(bool byEncoding, long offset)
ByEncoding = byEncoding;
Offset = offset;
}
-
- internal static BitfieldOffset Parse(string str)
- {
- if (str.IsNullOrEmpty())
- {
- throw new ArgumentException($"Cannot parse {nameof(BitfieldOffset)} from an empty or null string.", nameof(str));
- }
-
- long offset;
-
- if (str[0] == '#')
- {
- if (long.TryParse(str.Substring(1), out offset))
- {
- return new BitfieldOffset(true, offset);
- }
- }
- else
- {
- if (long.TryParse(str, out offset))
- {
- return new BitfieldOffset(false, offset);
- }
- }
-
- throw new ArgumentException($"{str} could not be parsed into a {nameof(BitfieldOffset)}.", nameof(str));
- }
}
///
@@ -254,29 +190,4 @@ public BitfieldEncoding(Signedness signedness, byte size)
Signedness = signedness;
Size = size;
}
-
- internal static BitfieldEncoding Parse(string str)
- {
- if (str.IsNullOrEmpty())
- {
- throw new ArgumentException($"Cannot parse {nameof(BitfieldEncoding)} from an empty or null String", nameof(str));
- }
-
- if (!byte.TryParse(str.Substring(1), out byte size))
- {
- throw new ArgumentException($"Could not parse {nameof(BitfieldEncoding)} from {str}", nameof(str));
- }
-
- if (char.ToLowerInvariant('i') == char.ToLowerInvariant(str[0]))
- {
- return new BitfieldEncoding(Signedness.Signed, size);
- }
-
- if (char.ToLowerInvariant('u') == char.ToLowerInvariant(str[0]))
- {
- return new BitfieldEncoding(Signedness.Unsigned, size);
- }
-
- throw new ArgumentException($"Could not parse {nameof(BitfieldEncoding)} from {str}", nameof(str));
- }
}
diff --git a/src/StackExchange.Redis/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI.Shipped.txt
index 8739d2d16..fc8e8b321 100644
--- a/src/StackExchange.Redis/PublicAPI.Shipped.txt
+++ b/src/StackExchange.Redis/PublicAPI.Shipped.txt
@@ -73,10 +73,8 @@ StackExchange.Redis.BitfieldEncoding.Signedness.get -> StackExchange.Redis.Signe
StackExchange.Redis.BitfieldEncoding.Size.get -> byte
StackExchange.Redis.BitfieldGet
StackExchange.Redis.BitfieldGet.BitfieldGet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset) -> void
-StackExchange.Redis.BitfieldGet.BitfieldGet(string! encoding, string! offset) -> void
StackExchange.Redis.BitfieldIncrby
StackExchange.Redis.BitfieldIncrby.BitfieldIncrby(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap) -> void
-StackExchange.Redis.BitfieldIncrby.BitfieldIncrby(string! encoding, string! offset, long increment) -> void
StackExchange.Redis.BitfieldIncrby.Increment.get -> long
StackExchange.Redis.BitfieldIncrby.OverflowHandling.get -> StackExchange.Redis.BitfieldOverflowHandling
StackExchange.Redis.BitfieldOffset
@@ -90,7 +88,6 @@ StackExchange.Redis.BitfieldOverflowHandling.Saturate = 1 -> StackExchange.Redis
StackExchange.Redis.BitfieldOverflowHandling.Wrap = 0 -> StackExchange.Redis.BitfieldOverflowHandling
StackExchange.Redis.BitfieldSet
StackExchange.Redis.BitfieldSet.BitfieldSet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value) -> void
-StackExchange.Redis.BitfieldSet.BitfieldSet(string! encoding, string! offset, long value) -> void
StackExchange.Redis.BitfieldSet.Value.get -> long
StackExchange.Redis.BitfieldSubCommand
StackExchange.Redis.BitfieldSubCommand.Encoding.get -> StackExchange.Redis.BitfieldEncoding
From 7554d6dc9ed66b65dcbb8a023878ee8885fdcc4c Mon Sep 17 00:00:00 2001
From: slorello89 <42971704+slorello89@users.noreply.github.com>
Date: Tue, 19 Apr 2022 10:26:07 -0400
Subject: [PATCH 05/14] some formatting comment updates
---
.../APITypes/BitfieldSubCommand.cs | 28 +++++++++++--------
.../Interfaces/IDatabase.cs | 4 +--
.../Interfaces/IDatabaseAsync.cs | 4 +--
3 files changed, 21 insertions(+), 15 deletions(-)
diff --git a/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs b/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
index 029be1f2c..055c91dea 100644
--- a/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
+++ b/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
@@ -4,17 +4,21 @@
namespace StackExchange.Redis;
///
-/// A subcommand for a bitfield.
+/// An abstract subcommand for a bitfield.
///
public abstract class BitfieldSubCommand
{
internal abstract int NumArgs { get; }
+
internal abstract void AddArgs(IList args);
+
internal virtual bool IsReadonly => false;
+
///
- /// The encoding of the sub-command. This might be a signed or unsigned integer.
+ /// The encoding of the sub-command. A signed or unsigned integer of a given size.
///
public BitfieldEncoding Encoding { get; }
+
///
/// The offset into the bitfield the subcommand will traverse.
///
@@ -29,14 +33,14 @@ internal BitfieldSubCommand(BitfieldEncoding encoding, BitfieldOffset offset)
}
///
-/// Represents a Bitfield GET, which returns the specified bitfield.
+/// Represents a Bitfield GET, which returns the number stored in the specified offset of a bitfield at the given encoding.
///
public sealed class BitfieldGet : BitfieldSubCommand
{
///
- /// Initializes a bitfield get subcommand
+ /// Initializes a bitfield GET subcommand
///
- /// the encoding of the subcommand.
+ /// The encoding of the subcommand.
/// The offset into the bitfield of the subcommand
public BitfieldGet(BitfieldEncoding encoding, BitfieldOffset offset) : base(encoding, offset)
{
@@ -55,7 +59,7 @@ internal override void AddArgs(IList args)
}
///
-/// Bitfield sub-command which set's the specified range of bits to the specified value.
+/// Bitfield subcommand which SETs the specified range of bits to the specified value.
///
public sealed class BitfieldSet : BitfieldSubCommand
{
@@ -65,7 +69,7 @@ public sealed class BitfieldSet : BitfieldSubCommand
public long Value { get; }
///
- /// Initializes a sub-command for a Bitfield Set.
+ /// Initializes a subcommand for a Bitfield SET.
///
/// The number's encoding.
/// The offset into the bitfield to set.
@@ -87,12 +91,12 @@ internal override void AddArgs(IList args)
}
///
-/// Bitfield sub-command which increments the number at the specified range of bits by the provided value
+/// Bitfield subcommand INCRBY, which increments the number at the specified range of bits by the provided value
///
public sealed class BitfieldIncrby : BitfieldSubCommand
{
///
- /// The value to set.
+ /// The value to increment by.
///
public long Increment { get; }
@@ -102,7 +106,7 @@ public sealed class BitfieldIncrby : BitfieldSubCommand
public BitfieldOverflowHandling OverflowHandling { get; }
///
- /// Initializes a sub-command for a Bitfield Set.
+ /// Initializes a sub-command for a Bitfield INCRBY.
///
/// The number's encoding.
/// The offset into the bitfield to set.
@@ -166,15 +170,17 @@ public BitfieldOffset(bool byEncoding, long offset)
}
///
-/// The encoding that a sub-command should use. This is either a signed or unsigned integer.
+/// The encoding that a sub-command should use. This is either a signed or unsigned integer of a specified length.
///
public readonly struct BitfieldEncoding
{
internal RedisValue AsRedisValue => $"{Signedness.SignChar()}{Size}";
+
///
/// The signedness of the integer.
///
public Signedness Signedness { get; }
+
///
/// The size of the integer.
///
diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs
index 183f774d3..b342e55bb 100644
--- a/src/StackExchange.Redis/Interfaces/IDatabase.cs
+++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs
@@ -2362,7 +2362,7 @@ IEnumerable SortedSetScan(RedisKey key,
long StringBitCount(RedisKey key, long start = 0, long end = -1, CommandFlags flags = CommandFlags.None);
///
- /// Pulls a single number out of a bitfield. Will execute a BITFIELD_RO if possible.
+ /// Pulls a single number out of a bitfield of the provided at the given offset. Will execute a BITFIELD_RO if possible.
///
/// The key for the string.
/// The encoding of the number.
@@ -2387,7 +2387,7 @@ IEnumerable SortedSetScan(RedisKey key,
///
- /// increments a single number number in a bitfield at the provided to the .
+ /// increments a single number number in a bitfield at the provided in the provided by the given .
///
/// The key for the string.
/// The encoding of the number.
diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
index cb777b8c7..d1fe47ef5 100644
--- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
+++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
@@ -2316,7 +2316,7 @@ IAsyncEnumerable SortedSetScanAsync(RedisKey key,
Task StringBitCountAsync(RedisKey key, long start = 0, long end = -1, CommandFlags flags = CommandFlags.None);
///
- /// Pulls a single number out of a bitfield. Will execute a BITFIELD_RO if possible.
+ /// Pulls a single number out of a bitfield of the provided at the given offset. Will execute a BITFIELD_RO if possible.
///
/// The key for the string.
/// The encoding of the number.
@@ -2340,7 +2340,7 @@ IAsyncEnumerable SortedSetScanAsync(RedisKey key,
Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None);
///
- /// increments a single number number in a bitfield at the provided to the .
+ /// Increments a single number number in a bitfield at the provided as if it were in the given by the given .
///
/// The key for the string.
/// The encoding of the number.
From c0fe65de7268499c49bca06309eda62fb9521319 Mon Sep 17 00:00:00 2001
From: slorello89 <42971704+slorello89@users.noreply.github.com>
Date: Tue, 19 Apr 2022 12:38:27 -0400
Subject: [PATCH 06/14] moving enums
---
.../{APITypes => Enums}/BitfieldOverflowHandling.cs | 0
src/StackExchange.Redis/{APITypes => Enums}/Signedness.cs | 0
2 files changed, 0 insertions(+), 0 deletions(-)
rename src/StackExchange.Redis/{APITypes => Enums}/BitfieldOverflowHandling.cs (100%)
rename src/StackExchange.Redis/{APITypes => Enums}/Signedness.cs (100%)
diff --git a/src/StackExchange.Redis/APITypes/BitfieldOverflowHandling.cs b/src/StackExchange.Redis/Enums/BitfieldOverflowHandling.cs
similarity index 100%
rename from src/StackExchange.Redis/APITypes/BitfieldOverflowHandling.cs
rename to src/StackExchange.Redis/Enums/BitfieldOverflowHandling.cs
diff --git a/src/StackExchange.Redis/APITypes/Signedness.cs b/src/StackExchange.Redis/Enums/Signedness.cs
similarity index 100%
rename from src/StackExchange.Redis/APITypes/Signedness.cs
rename to src/StackExchange.Redis/Enums/Signedness.cs
From 3928113934dbc024d4e686532b318a62b9dbef80 Mon Sep 17 00:00:00 2001
From: slorello89 <42971704+slorello89@users.noreply.github.com>
Date: Tue, 19 Apr 2022 12:44:42 -0400
Subject: [PATCH 07/14] using new remarks pattern nick introduced
---
src/StackExchange.Redis/Interfaces/IDatabase.cs | 12 ++++++------
src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs | 12 ++++++------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs
index 1262821e6..1ee79ccf4 100644
--- a/src/StackExchange.Redis/Interfaces/IDatabase.cs
+++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs
@@ -2500,8 +2500,8 @@ IEnumerable SortedSetScan(RedisKey key,
/// The offset into the bitfield to pull the number from.
/// The Commands for the operation.
/// The number of the given at the provided .
- /// https://redis.io/commands/bitfield
- /// https://redis.io/commands/bitfield_ro
+ ///
+ ///
long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None);
///
@@ -2513,7 +2513,7 @@ IEnumerable SortedSetScan(RedisKey key,
/// the value to set the bitfield to.
/// The Commands for the operation.
/// The previous value as am at the provided .
- /// https://redis.io/commands/bitfield
+ ///
long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None);
@@ -2527,7 +2527,7 @@ IEnumerable SortedSetScan(RedisKey key,
/// The way integer overflows are handled.
/// The Commands for the operation.
/// The new value of the given at the provided after the incrby is applied, represented as an . Returns if the operation fails.
- /// https://redis.io/commands/bitfield
+ ///
long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None);
@@ -2538,8 +2538,8 @@ IEnumerable SortedSetScan(RedisKey key,
/// The subcommands to execute against the bitfield.
/// The flags for this operation.
/// An array of numbers corresponding to the result of each sub-command. For increment subcommands, these can be null.
- /// https://redis.io/commands/bitfield
- /// https://redis.io/commands/bitfield_ro
+ ///
+ ///
long?[] StringBitfield(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None);
///
diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
index 8cf8f9ee7..945c6ee18 100644
--- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
+++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
@@ -2453,8 +2453,8 @@ IAsyncEnumerable SortedSetScanAsync(RedisKey key,
/// The offset into the bitfield to pull the number from.
/// The Commands for the operation.
/// The number of the given at the provided .
- /// https://redis.io/commands/bitfield
- /// https://redis.io/commands/bitfield_ro
+ ///
+ ///
Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None);
///
@@ -2466,7 +2466,7 @@ IAsyncEnumerable SortedSetScanAsync(RedisKey key,
/// the value to set the bitfield to.
/// The Commands for the operation.
/// The previous value as am at the provided .
- /// https://redis.io/commands/bitfield
+ ///
Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None);
///
@@ -2479,7 +2479,7 @@ IAsyncEnumerable SortedSetScanAsync(RedisKey key,
/// The way integer overflows are handled.
/// The Commands for the operation.
/// The new value of the given at the provided after the incrby is applied, represented as an . Returns if the operation fails.
- /// https://redis.io/commands/bitfield
+ ///
Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None);
///
@@ -2489,8 +2489,8 @@ IAsyncEnumerable SortedSetScanAsync(RedisKey key,
/// The subcommands to execute against the bitfield.
/// The flags for this operation.
/// An array of numbers corresponding to the result of each sub-command. For increment subcommands, these can be null.
- /// https://redis.io/commands/bitfield
- /// https://redis.io/commands/bitfield_ro
+ ///
+ ///
Task StringBitfieldAsync(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None);
///
From b3c16c4cc04bae7672824b4043f24643cecc00d8 Mon Sep 17 00:00:00 2001
From: slorello89 <42971704+slorello89@users.noreply.github.com>
Date: Tue, 19 Apr 2022 16:45:51 -0400
Subject: [PATCH 08/14] properly checking feature flag
---
src/StackExchange.Redis/RedisDatabase.cs | 40 +++++++++++++-----------
src/StackExchange.Redis/RedisFeatures.cs | 5 +++
2 files changed, 26 insertions(+), 19 deletions(-)
diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs
index f9a30d416..3552f1f10 100644
--- a/src/StackExchange.Redis/RedisDatabase.cs
+++ b/src/StackExchange.Redis/RedisDatabase.cs
@@ -2748,26 +2748,26 @@ public long StringBitCount(RedisKey key, long start = 0, long end = -1, CommandF
public long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, new BitfieldGet(encoding, offset), flags);
- return ExecuteSync(msg, ResultProcessor.Int64);
+ var msg = GetBitfieldMessage(key, new BitfieldGet(encoding, offset), flags, out ServerEndPoint? server);
+ return ExecuteSync(msg, ResultProcessor.Int64, server);
}
public long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, new BitfieldSet(encoding, offset, value), flags);
- return ExecuteSync(msg, ResultProcessor.Int64);
+ var msg = GetBitfieldMessage(key, new BitfieldSet(encoding, offset, value), flags, out ServerEndPoint? server);
+ return ExecuteSync(msg, ResultProcessor.Int64, server);
}
public long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, new BitfieldIncrby(encoding, offset, increment, overflowHandling), flags);
- return ExecuteSync(msg, ResultProcessor.NullableInt64);
+ var msg = GetBitfieldMessage(key, new BitfieldIncrby(encoding, offset, increment, overflowHandling), flags, out ServerEndPoint? server);
+ return ExecuteSync(msg, ResultProcessor.NullableInt64, server);
}
public long?[] StringBitfield(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, subcommands, flags);
- return ExecuteSync(msg, ResultProcessor.NullableInt64Array, defaultValue: Array.Empty());
+ var msg = GetBitfieldMessage(key, subcommands, flags, out ServerEndPoint? server);
+ return ExecuteSync(msg, ResultProcessor.NullableInt64Array, defaultValue: Array.Empty(), server: server);
}
public Task StringBitCountAsync(RedisKey key, long start = 0, long end = -1, CommandFlags flags = CommandFlags.None)
@@ -2778,26 +2778,26 @@ public Task StringBitCountAsync(RedisKey key, long start = 0, long end = -
public Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, new BitfieldGet(encoding, offset), flags);
- return ExecuteAsync(msg, ResultProcessor.Int64);
+ var msg = GetBitfieldMessage(key, new BitfieldGet(encoding, offset), flags, out ServerEndPoint? server);
+ return ExecuteAsync(msg, ResultProcessor.Int64, server);
}
public Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, new BitfieldSet(encoding, offset, value), flags);
+ var msg = GetBitfieldMessage(key, new BitfieldSet(encoding, offset, value), flags, out ServerEndPoint? server);
return ExecuteAsync(msg, ResultProcessor.Int64);
}
public Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, new BitfieldIncrby(encoding, offset, increment, overflowHandling), flags);
- return ExecuteAsync(msg, ResultProcessor.NullableInt64);
+ var msg = GetBitfieldMessage(key, new BitfieldIncrby(encoding, offset, increment, overflowHandling), flags, out ServerEndPoint? server);
+ return ExecuteAsync(msg, ResultProcessor.NullableInt64, server);
}
public Task StringBitfieldAsync(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, subcommands, flags);
- return ExecuteAsync(msg, ResultProcessor.NullableInt64Array, defaultValue: Array.Empty());
+ var msg = GetBitfieldMessage(key, subcommands, flags, out ServerEndPoint? server);
+ return ExecuteAsync(msg, ResultProcessor.NullableInt64Array, defaultValue: Array.Empty(), server: server);
}
public long StringBitOperation(Bitwise operation, RedisKey destination, RedisKey first, RedisKey second, CommandFlags flags = CommandFlags.None)
@@ -3130,12 +3130,13 @@ public Task StringSetRangeAsync(RedisKey key, long offset, RedisValu
_ => throw new ArgumentException("Expiry time must be either Utc or Local", nameof(when)),
};
- private Message GetBitfieldMessage(in RedisKey key, BitfieldSubCommand subcommand, CommandFlags flags)
+ private Message GetBitfieldMessage(in RedisKey key, BitfieldSubCommand subcommand, CommandFlags flags, out ServerEndPoint? server)
{
+ var features = GetFeatures(key, flags, out server);
var args = new List(subcommand.NumArgs);
subcommand.AddArgs(args);
RedisCommand command = RedisCommand.BITFIELD;
- if (subcommand is BitfieldGet && multiplexer.GetServer(multiplexer.EndPoints[0]).Version >= RedisFeatures.v6_2_0)
+ if (subcommand is BitfieldGet && features.ReadOnlyBitfield)
{
command = RedisCommand.BITFIELD_RO;
}
@@ -3143,11 +3144,12 @@ private Message GetBitfieldMessage(in RedisKey key, BitfieldSubCommand subcomman
return Message.Create(Database, flags, command, key, args.ToArray());
}
- private Message GetBitfieldMessage(in RedisKey key, BitfieldSubCommand[] subCommands, CommandFlags flags)
+ private Message GetBitfieldMessage(in RedisKey key, BitfieldSubCommand[] subCommands, CommandFlags flags, out ServerEndPoint? server)
{
+ var features = GetFeatures(key, flags, out server);
var args = new List(subCommands.Sum(sc => sc.NumArgs));
var canBeReadonly = subCommands.All(sc => sc.IsReadonly);
- var command = canBeReadonly && multiplexer.GetServer(multiplexer.EndPoints[0]).Version >= RedisFeatures.v6_2_0 ? RedisCommand.BITFIELD_RO : RedisCommand.BITFIELD;
+ var command = canBeReadonly &&features.ReadOnlyBitfield ? RedisCommand.BITFIELD_RO : RedisCommand.BITFIELD;
foreach (var subcommand in subCommands)
{
diff --git a/src/StackExchange.Redis/RedisFeatures.cs b/src/StackExchange.Redis/RedisFeatures.cs
index a2dcee19e..1aa80e122 100644
--- a/src/StackExchange.Redis/RedisFeatures.cs
+++ b/src/StackExchange.Redis/RedisFeatures.cs
@@ -242,6 +242,11 @@ public RedisFeatures(Version version)
///
public bool KeyTouch => Version >= v3_2_1;
+ ///
+ /// Is BITFIELD_RO available?
+ ///
+ internal bool ReadOnlyBitfield => Version > v6_2_0;
+
///
/// Does the server prefer 'replica' terminology - 'REPLICAOF', etc?
///
From d3cc041bec284d8e0064964fb3c6e41108808b43 Mon Sep 17 00:00:00 2001
From: slorello89 <42971704+slorello89@users.noreply.github.com>
Date: Wed, 27 Apr 2022 21:28:08 -0400
Subject: [PATCH 09/14] decreasing public-api surface area, using a builder.
---
.../APITypes/BitfieldCommandBuilder.cs | 159 ++++++++++++++
.../APITypes/BitfieldSubCommand.cs | 199 ------------------
.../Interfaces/IDatabase.cs | 7 +-
.../Interfaces/IDatabaseAsync.cs | 7 +-
.../KeyspaceIsolation/DatabaseWrapper.cs | 4 +-
.../KeyspaceIsolation/WrapperBase.cs | 4 +-
src/StackExchange.Redis/PublicAPI.Shipped.txt | 21 +-
src/StackExchange.Redis/RedisDatabase.cs | 51 +----
tests/StackExchange.Redis.Tests/Bitfield.cs | 20 +-
9 files changed, 199 insertions(+), 273 deletions(-)
create mode 100644 src/StackExchange.Redis/APITypes/BitfieldCommandBuilder.cs
delete mode 100644 src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
diff --git a/src/StackExchange.Redis/APITypes/BitfieldCommandBuilder.cs b/src/StackExchange.Redis/APITypes/BitfieldCommandBuilder.cs
new file mode 100644
index 000000000..4c7e14697
--- /dev/null
+++ b/src/StackExchange.Redis/APITypes/BitfieldCommandBuilder.cs
@@ -0,0 +1,159 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace StackExchange.Redis;
+
+///
+/// Builder for bitfield commands that take multiple sub-commands.
+///
+public class BitfieldCommandBuilder
+{
+ private readonly LinkedList _args = new LinkedList();
+ private bool _eligibleForReadOnly;
+
+ ///
+ /// Builds a subcommand for a Bitfield GET, which returns the number stored in the specified offset of a bitfield at the given encoding.
+ ///
+ /// The encoding for the subcommand.
+ /// The offset into the bitfield for the subcommand.
+ public BitfieldCommandBuilder BitfieldGet(BitfieldEncoding encoding, BitfieldOffset offset)
+ {
+ _eligibleForReadOnly = true;
+ _args.AddLast(RedisLiterals.GET);
+ _args.AddLast(encoding.RedisValue);
+ _args.AddLast(offset.RedisValue);
+ return this;
+ }
+
+ ///
+ /// Builds a Bitfield subcommand which SETs the specified range of bits to the specified value.
+ ///
+ /// The encoding of the subcommand.
+ /// The offset of the subcommand.
+ /// The value to set.
+ public BitfieldCommandBuilder BitfieldSet(BitfieldEncoding encoding, BitfieldOffset offset, long value)
+ {
+ _eligibleForReadOnly = false;
+ _args.AddLast(RedisLiterals.SET);
+ _args.AddLast(encoding.RedisValue);
+ _args.AddLast(offset.RedisValue);
+ _args.AddLast(value);
+ return this;
+ }
+
+ ///
+ /// Builds a subcommand for Bitfield INCRBY, which increments the number at the specified range of bits by the provided value
+ ///
+ /// The number's encoding.
+ /// The offset into the bitfield to increment.
+ /// The value to increment by.
+ /// How overflows will be handled when incrementing.
+ public BitfieldCommandBuilder BitfieldIncrby(BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap)
+ {
+ _eligibleForReadOnly = false;
+ if (overflowHandling != BitfieldOverflowHandling.Wrap)
+ {
+ _args.AddLast(RedisLiterals.OVERFLOW);
+ _args.AddLast(overflowHandling.AsRedisValue());
+ }
+
+ _args.AddLast(RedisLiterals.INCRBY);
+ _args.AddLast(encoding.RedisValue);
+ _args.AddLast(offset.RedisValue);
+ _args.AddLast(increment);
+ return this;
+ }
+
+ internal BitfieldCommandMessage Build(int db, RedisKey key, CommandFlags flags, RedisBase redisBase, out ServerEndPoint? server)
+ {
+ var features = redisBase.GetFeatures(key, flags, out server);
+ var command = _eligibleForReadOnly && features.ReadOnlyBitfield ? RedisCommand.BITFIELD_RO : RedisCommand.BITFIELD;
+ return new BitfieldCommandMessage(db, flags, key, command, _args);
+ }
+}
+
+internal class BitfieldCommandMessage : Message
+{
+ private readonly LinkedList _args;
+ private readonly RedisKey _key;
+ public BitfieldCommandMessage(int db, CommandFlags flags, RedisKey key, RedisCommand command, LinkedList args) : base(db, flags, command)
+ {
+ _key = key;
+ _args = args;
+ }
+
+ public override int ArgCount => 1 + _args.Count;
+
+ protected override void WriteImpl(PhysicalConnection physical)
+ {
+ physical.WriteHeader(Command, ArgCount);
+ physical.Write(_key);
+ foreach (var arg in _args)
+ {
+ physical.WriteBulkString(arg);
+ }
+ }
+}
+
+///
+/// An offset into a bitfield. This is either a literal offset (number of bits from the beginning of the bitfield) or an
+/// encoding based offset, based off the encoding of the sub-command.
+///
+public readonly struct BitfieldOffset
+{
+ ///
+ /// Returns the BitfieldOffset as a RedisValue
+ ///
+ internal RedisValue RedisValue => $"{(ByEncoding ? "#" : string.Empty)}{Offset}";
+
+ ///
+ /// Whether or not the BitfieldOffset will work off of the sub-commands integer encoding.
+ ///
+ public bool ByEncoding { get; }
+
+ ///
+ /// The number of either bits or encoded integers to offset into the bitfield.
+ ///
+ public long Offset { get; }
+
+ ///
+ /// Initializes a bitfield offset
+ ///
+ /// Whether or not the BitfieldOffset will work off of the sub-commands integer encoding.
+ /// The number of either bits or encoded integers to offset into the bitfield.
+ public BitfieldOffset(bool byEncoding, long offset)
+ {
+ ByEncoding = byEncoding;
+ Offset = offset;
+ }
+}
+
+///
+/// The encoding that a sub-command should use. This is either a signed or unsigned integer of a specified length.
+///
+public readonly struct BitfieldEncoding
+{
+ internal RedisValue RedisValue => $"{Signedness.SignChar()}{Size}";
+
+ ///
+ /// The signedness of the integer.
+ ///
+ public Signedness Signedness { get; }
+
+ ///
+ /// The size of the integer.
+ ///
+ public byte Size { get; }
+
+ ///
+ /// Initializes the BitfieldEncoding.
+ ///
+ /// The encoding's
+ /// The size of the integer.
+ public BitfieldEncoding(Signedness signedness, byte size)
+ {
+ Signedness = signedness;
+ Size = size;
+ }
+}
diff --git a/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs b/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
deleted file mode 100644
index 055c91dea..000000000
--- a/src/StackExchange.Redis/APITypes/BitfieldSubCommand.cs
+++ /dev/null
@@ -1,199 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace StackExchange.Redis;
-
-///
-/// An abstract subcommand for a bitfield.
-///
-public abstract class BitfieldSubCommand
-{
- internal abstract int NumArgs { get; }
-
- internal abstract void AddArgs(IList args);
-
- internal virtual bool IsReadonly => false;
-
- ///
- /// The encoding of the sub-command. A signed or unsigned integer of a given size.
- ///
- public BitfieldEncoding Encoding { get; }
-
- ///
- /// The offset into the bitfield the subcommand will traverse.
- ///
- public BitfieldOffset Offset { get; }
-
- internal BitfieldSubCommand(BitfieldEncoding encoding, BitfieldOffset offset)
- {
- Encoding = encoding;
- Offset = offset;
- }
-
-}
-
-///
-/// Represents a Bitfield GET, which returns the number stored in the specified offset of a bitfield at the given encoding.
-///
-public sealed class BitfieldGet : BitfieldSubCommand
-{
- ///
- /// Initializes a bitfield GET subcommand
- ///
- /// The encoding of the subcommand.
- /// The offset into the bitfield of the subcommand
- public BitfieldGet(BitfieldEncoding encoding, BitfieldOffset offset) : base(encoding, offset)
- {
- }
-
- internal override bool IsReadonly => true;
-
- internal override int NumArgs => 3;
-
- internal override void AddArgs(IList args)
- {
- args.Add(RedisLiterals.GET);
- args.Add(Encoding.AsRedisValue);
- args.Add(Offset.AsRedisValue);
- }
-}
-
-///
-/// Bitfield subcommand which SETs the specified range of bits to the specified value.
-///
-public sealed class BitfieldSet : BitfieldSubCommand
-{
- ///
- /// The value to set.
- ///
- public long Value { get; }
-
- ///
- /// Initializes a subcommand for a Bitfield SET.
- ///
- /// The number's encoding.
- /// The offset into the bitfield to set.
- /// The value to set.
- public BitfieldSet(BitfieldEncoding encoding, BitfieldOffset offset, long value) : base(encoding, offset)
- {
- Value = value;
- }
-
- internal override int NumArgs => 4;
-
- internal override void AddArgs(IList args)
- {
- args.Add(RedisLiterals.SET);
- args.Add(Encoding.AsRedisValue);
- args.Add(Offset.AsRedisValue);
- args.Add(Value);
- }
-}
-
-///
-/// Bitfield subcommand INCRBY, which increments the number at the specified range of bits by the provided value
-///
-public sealed class BitfieldIncrby : BitfieldSubCommand
-{
- ///
- /// The value to increment by.
- ///
- public long Increment { get; }
-
- ///
- /// Determines how overflows are handled for the bitfield.
- ///
- public BitfieldOverflowHandling OverflowHandling { get; }
-
- ///
- /// Initializes a sub-command for a Bitfield INCRBY.
- ///
- /// The number's encoding.
- /// The offset into the bitfield to set.
- /// The value to set.
- /// How overflows will be handled when incrementing.
- public BitfieldIncrby(BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap) : base(encoding, offset)
- {
- Increment = increment;
- OverflowHandling = overflowHandling;
- }
-
- internal override int NumArgs => OverflowHandling == BitfieldOverflowHandling.Wrap ? 4 : 6;
-
- internal override void AddArgs(IList args)
- {
- if (OverflowHandling != BitfieldOverflowHandling.Wrap)
- {
- args.Add(RedisLiterals.OVERFLOW);
- args.Add(OverflowHandling.AsRedisValue());
- }
- args.Add(RedisLiterals.INCRBY);
- args.Add(Encoding.AsRedisValue);
- args.Add(Offset.AsRedisValue);
- args.Add(Increment);
- }
-}
-
-
-
-///
-/// An offset into a bitfield. This is either a literal offset (number of bits from the beginning of the bitfield) or an
-/// encoding based offset, based off the encoding of the sub-command.
-///
-public readonly struct BitfieldOffset
-{
- ///
- /// Returns the BitfieldOffset as a RedisValue
- ///
- internal RedisValue AsRedisValue => $"{(ByEncoding ? "#" : string.Empty)}{Offset}";
-
- ///
- /// Whether or not the BitfieldOffset will work off of the sub-commands integer encoding.
- ///
- public bool ByEncoding { get; }
-
- ///
- /// The number of either bits or encoded integers to offset into the bitfield.
- ///
- public long Offset { get; }
-
- ///
- /// Initializes a bitfield offset
- ///
- /// Whether or not the BitfieldOffset will work off of the sub-commands integer encoding.
- /// The number of either bits or encoded integers to offset into the bitfield.
- public BitfieldOffset(bool byEncoding, long offset)
- {
- ByEncoding = byEncoding;
- Offset = offset;
- }
-}
-
-///
-/// The encoding that a sub-command should use. This is either a signed or unsigned integer of a specified length.
-///
-public readonly struct BitfieldEncoding
-{
- internal RedisValue AsRedisValue => $"{Signedness.SignChar()}{Size}";
-
- ///
- /// The signedness of the integer.
- ///
- public Signedness Signedness { get; }
-
- ///
- /// The size of the integer.
- ///
- public byte Size { get; }
-
- ///
- /// Initializes the BitfieldEncoding.
- ///
- /// The encoding's
- /// The size of the integer.
- public BitfieldEncoding(Signedness signedness, byte size)
- {
- Signedness = signedness;
- Size = size;
- }
-}
diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs
index 1ee79ccf4..2c8111562 100644
--- a/src/StackExchange.Redis/Interfaces/IDatabase.cs
+++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs
@@ -2532,15 +2532,16 @@ IEnumerable SortedSetScan(RedisKey key,
///
- /// Executes a set of Bitfield against the bitfield at the provided . Will run as a BITFIELD_RO if all operations are read-only and the command is available.
+ /// Executes a set of Bitfield subcommands as constructed by the against the bitfield at the provided .
+ /// Will run as a BITFIELD_RO if all operations are read-only and the command is available.
///
/// The key of the string.
- /// The subcommands to execute against the bitfield.
+ /// The subcommands to execute against the bitfield.
/// The flags for this operation.
/// An array of numbers corresponding to the result of each sub-command. For increment subcommands, these can be null.
///
///
- long?[] StringBitfield(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None);
+ long?[] StringBitfield(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None);
///
/// Perform a bitwise operation between multiple keys (containing string values) and store the result in the destination key.
diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
index 945c6ee18..64027c4c8 100644
--- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
+++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
@@ -2483,15 +2483,16 @@ IAsyncEnumerable SortedSetScanAsync(RedisKey key,
Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None);
///
- /// Executes a set of Bitfield against the bitfield at the provided . Will run as a BITFIELD_RO if all operations are read-only and the command is available.
+ /// Executes a set of Bitfield subcommands as constructed by the against the bitfield at the provided .
+ /// Will run as a BITFIELD_RO if all operations are read-only and the command is available.
///
/// The key of the string.
- /// The subcommands to execute against the bitfield.
+ /// The subcommands to execute against the bitfield.
/// The flags for this operation.
/// An array of numbers corresponding to the result of each sub-command. For increment subcommands, these can be null.
///
///
- Task StringBitfieldAsync(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None);
+ Task StringBitfieldAsync(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None);
///
/// Perform a bitwise operation between multiple keys (containing string values) and store the result in the destination key.
diff --git a/src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs b/src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs
index ae5c272b0..6760525ec 100644
--- a/src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs
+++ b/src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs
@@ -583,8 +583,8 @@ public long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldO
public long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None) =>
Inner.StringBitfieldIncrement(ToInner(key), encoding, offset, increment, overflowHandling, flags);
- public long?[] StringBitfield(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None) =>
- Inner.StringBitfield(key, subcommands, flags);
+ public long?[] StringBitfield(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfield(key, builder, flags);
public long StringBitOperation(Bitwise operation, RedisKey destination, RedisKey[] keys, CommandFlags flags = CommandFlags.None) =>
Inner.StringBitOperation(operation, ToInner(destination), ToInner(keys), flags);
diff --git a/src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs b/src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs
index 1108b4a50..e24d11d04 100644
--- a/src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs
+++ b/src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs
@@ -601,8 +601,8 @@ public Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding
public Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None) =>
Inner.StringBitfieldIncrementAsync(ToInner(key), encoding, offset, increment, overflowHandling, flags);
- public Task StringBitfieldAsync(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None) =>
- Inner.StringBitfieldAsync(ToInner(key), subcommands, flags);
+ public Task StringBitfieldAsync(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldAsync(ToInner(key), builder, flags);
public Task StringBitOperationAsync(Bitwise operation, RedisKey destination, RedisKey[] keys, CommandFlags flags = CommandFlags.None) =>
Inner.StringBitOperationAsync(operation, ToInner(destination), ToInner(keys), flags);
diff --git a/src/StackExchange.Redis/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI.Shipped.txt
index ec39ec063..4b335efe3 100644
--- a/src/StackExchange.Redis/PublicAPI.Shipped.txt
+++ b/src/StackExchange.Redis/PublicAPI.Shipped.txt
@@ -66,17 +66,16 @@ StackExchange.Redis.BacklogPolicy.AbortPendingOnConnectionFailure.init -> void
StackExchange.Redis.BacklogPolicy.BacklogPolicy() -> void
StackExchange.Redis.BacklogPolicy.QueueWhileDisconnected.get -> bool
StackExchange.Redis.BacklogPolicy.QueueWhileDisconnected.init -> void
+StackExchange.Redis.BitfieldCommandBuilder
+StackExchange.Redis.BitfieldCommandBuilder.BitfieldCommandBuilder() -> void
+StackExchange.Redis.BitfieldCommandBuilder.BitfieldGet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset) -> StackExchange.Redis.BitfieldCommandBuilder!
+StackExchange.Redis.BitfieldCommandBuilder.BitfieldIncrby(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap) -> StackExchange.Redis.BitfieldCommandBuilder!
+StackExchange.Redis.BitfieldCommandBuilder.BitfieldSet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value) -> StackExchange.Redis.BitfieldCommandBuilder!
StackExchange.Redis.BitfieldEncoding
StackExchange.Redis.BitfieldEncoding.BitfieldEncoding() -> void
StackExchange.Redis.BitfieldEncoding.BitfieldEncoding(StackExchange.Redis.Signedness signedness, byte size) -> void
StackExchange.Redis.BitfieldEncoding.Signedness.get -> StackExchange.Redis.Signedness
StackExchange.Redis.BitfieldEncoding.Size.get -> byte
-StackExchange.Redis.BitfieldGet
-StackExchange.Redis.BitfieldGet.BitfieldGet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset) -> void
-StackExchange.Redis.BitfieldIncrby
-StackExchange.Redis.BitfieldIncrby.BitfieldIncrby(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap) -> void
-StackExchange.Redis.BitfieldIncrby.Increment.get -> long
-StackExchange.Redis.BitfieldIncrby.OverflowHandling.get -> StackExchange.Redis.BitfieldOverflowHandling
StackExchange.Redis.BitfieldOffset
StackExchange.Redis.BitfieldOffset.BitfieldOffset() -> void
StackExchange.Redis.BitfieldOffset.BitfieldOffset(bool byEncoding, long offset) -> void
@@ -86,12 +85,6 @@ StackExchange.Redis.BitfieldOverflowHandling
StackExchange.Redis.BitfieldOverflowHandling.Fail = 2 -> StackExchange.Redis.BitfieldOverflowHandling
StackExchange.Redis.BitfieldOverflowHandling.Saturate = 1 -> StackExchange.Redis.BitfieldOverflowHandling
StackExchange.Redis.BitfieldOverflowHandling.Wrap = 0 -> StackExchange.Redis.BitfieldOverflowHandling
-StackExchange.Redis.BitfieldSet
-StackExchange.Redis.BitfieldSet.BitfieldSet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value) -> void
-StackExchange.Redis.BitfieldSet.Value.get -> long
-StackExchange.Redis.BitfieldSubCommand
-StackExchange.Redis.BitfieldSubCommand.Encoding.get -> StackExchange.Redis.BitfieldEncoding
-StackExchange.Redis.BitfieldSubCommand.Offset.get -> StackExchange.Redis.BitfieldOffset
StackExchange.Redis.Bitwise
StackExchange.Redis.Bitwise.And = 0 -> StackExchange.Redis.Bitwise
StackExchange.Redis.Bitwise.Not = 3 -> StackExchange.Redis.Bitwise
@@ -709,7 +702,7 @@ StackExchange.Redis.IDatabase.StringBitCount(StackExchange.Redis.RedisKey key, l
StackExchange.Redis.IDatabase.StringBitOperation(StackExchange.Redis.Bitwise operation, StackExchange.Redis.RedisKey destination, StackExchange.Redis.RedisKey first, StackExchange.Redis.RedisKey second = default(StackExchange.Redis.RedisKey), StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.IDatabase.StringBitOperation(StackExchange.Redis.Bitwise operation, StackExchange.Redis.RedisKey destination, StackExchange.Redis.RedisKey[]! keys, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.IDatabase.StringBitPosition(StackExchange.Redis.RedisKey key, bool bit, long start = 0, long end = -1, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
-StackExchange.Redis.IDatabase.StringBitfield(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldSubCommand![]! subcommands, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?[]!
+StackExchange.Redis.IDatabase.StringBitfield(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldCommandBuilder! builder, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?[]!
StackExchange.Redis.IDatabase.StringBitfieldGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.IDatabase.StringBitfieldIncrement(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?
StackExchange.Redis.IDatabase.StringBitfieldSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
@@ -923,7 +916,7 @@ StackExchange.Redis.IDatabaseAsync.StreamReadGroupAsync(StackExchange.Redis.Stre
StackExchange.Redis.IDatabaseAsync.StreamTrimAsync(StackExchange.Redis.RedisKey key, int maxLength, bool useApproximateMaxLength = false, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringAppendAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitCountAsync(StackExchange.Redis.RedisKey key, long start = 0, long end = -1, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
-StackExchange.Redis.IDatabaseAsync.StringBitfieldAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldSubCommand![]! subcommands, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
+StackExchange.Redis.IDatabaseAsync.StringBitfieldAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldCommandBuilder! builder, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitfieldGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitfieldIncrementAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitfieldSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs
index 3552f1f10..8419c51ff 100644
--- a/src/StackExchange.Redis/RedisDatabase.cs
+++ b/src/StackExchange.Redis/RedisDatabase.cs
@@ -2748,25 +2748,25 @@ public long StringBitCount(RedisKey key, long start = 0, long end = -1, CommandF
public long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, new BitfieldGet(encoding, offset), flags, out ServerEndPoint? server);
+ var msg = new BitfieldCommandBuilder().BitfieldGet(encoding, offset).Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteSync(msg, ResultProcessor.Int64, server);
}
public long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, new BitfieldSet(encoding, offset, value), flags, out ServerEndPoint? server);
+ var msg = new BitfieldCommandBuilder().BitfieldSet(encoding, offset, value).Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteSync(msg, ResultProcessor.Int64, server);
}
public long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, new BitfieldIncrby(encoding, offset, increment, overflowHandling), flags, out ServerEndPoint? server);
+ var msg = new BitfieldCommandBuilder().BitfieldIncrby(encoding, offset, increment, overflowHandling).Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteSync(msg, ResultProcessor.NullableInt64, server);
}
- public long?[] StringBitfield(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None)
+ public long?[] StringBitfield(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, subcommands, flags, out ServerEndPoint? server);
+ var msg = builder.Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteSync(msg, ResultProcessor.NullableInt64Array, defaultValue: Array.Empty(), server: server);
}
@@ -2778,25 +2778,25 @@ public Task StringBitCountAsync(RedisKey key, long start = 0, long end = -
public Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, new BitfieldGet(encoding, offset), flags, out ServerEndPoint? server);
+ var msg = new BitfieldCommandBuilder().BitfieldGet(encoding, offset).Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteAsync(msg, ResultProcessor.Int64, server);
}
public Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, new BitfieldSet(encoding, offset, value), flags, out ServerEndPoint? server);
- return ExecuteAsync(msg, ResultProcessor.Int64);
+ var msg = new BitfieldCommandBuilder().BitfieldSet(encoding, offset, value).Build(Database, key, flags, this, out ServerEndPoint? server);
+ return ExecuteAsync(msg, ResultProcessor.Int64, server);
}
public Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, new BitfieldIncrby(encoding, offset, increment, overflowHandling), flags, out ServerEndPoint? server);
+ var msg = new BitfieldCommandBuilder().BitfieldIncrby(encoding, offset, increment, overflowHandling).Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteAsync(msg, ResultProcessor.NullableInt64, server);
}
- public Task StringBitfieldAsync(RedisKey key, BitfieldSubCommand[] subcommands, CommandFlags flags = CommandFlags.None)
+ public Task StringBitfieldAsync(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None)
{
- var msg = GetBitfieldMessage(key, subcommands, flags, out ServerEndPoint? server);
+ var msg = builder.Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteAsync(msg, ResultProcessor.NullableInt64Array, defaultValue: Array.Empty(), server: server);
}
@@ -3130,35 +3130,6 @@ public Task StringSetRangeAsync(RedisKey key, long offset, RedisValu
_ => throw new ArgumentException("Expiry time must be either Utc or Local", nameof(when)),
};
- private Message GetBitfieldMessage(in RedisKey key, BitfieldSubCommand subcommand, CommandFlags flags, out ServerEndPoint? server)
- {
- var features = GetFeatures(key, flags, out server);
- var args = new List(subcommand.NumArgs);
- subcommand.AddArgs(args);
- RedisCommand command = RedisCommand.BITFIELD;
- if (subcommand is BitfieldGet && features.ReadOnlyBitfield)
- {
- command = RedisCommand.BITFIELD_RO;
- }
-
- return Message.Create(Database, flags, command, key, args.ToArray());
- }
-
- private Message GetBitfieldMessage(in RedisKey key, BitfieldSubCommand[] subCommands, CommandFlags flags, out ServerEndPoint? server)
- {
- var features = GetFeatures(key, flags, out server);
- var args = new List(subCommands.Sum(sc => sc.NumArgs));
- var canBeReadonly = subCommands.All(sc => sc.IsReadonly);
- var command = canBeReadonly &&features.ReadOnlyBitfield ? RedisCommand.BITFIELD_RO : RedisCommand.BITFIELD;
-
- foreach (var subcommand in subCommands)
- {
- subcommand.AddArgs(args);
- }
-
- return Message.Create(Database, flags, command, key, args.ToArray());
- }
-
private Message GetCopyMessage(in RedisKey sourceKey, RedisKey destinationKey, int destinationDatabase, bool replace, CommandFlags flags) =>
destinationDatabase switch
{
diff --git a/tests/StackExchange.Redis.Tests/Bitfield.cs b/tests/StackExchange.Redis.Tests/Bitfield.cs
index 0f52a191c..5a1c9e460 100644
--- a/tests/StackExchange.Redis.Tests/Bitfield.cs
+++ b/tests/StackExchange.Redis.Tests/Bitfield.cs
@@ -81,16 +81,16 @@ public async Task TestBitfieldMulti()
RedisKey key = Me();
db.KeyDelete(key);
- var set1 = new BitfieldSet(new BitfieldEncoding(Signedness.Unsigned, 3), new BitfieldOffset(false, 5), 7);
- var get1 = new BitfieldGet(new BitfieldEncoding(Signedness.Unsigned, 3), new BitfieldOffset(false, 5));
- var incr1 = new BitfieldIncrby(new BitfieldEncoding(Signedness.Unsigned, 3), new BitfieldOffset(false, 5), -1);
-
- var set2 = new BitfieldSet(new BitfieldEncoding(Signedness.Signed, 45), new BitfieldOffset(true, 1), 17592186044415);
- var get2 = new BitfieldGet(new BitfieldEncoding(Signedness.Signed, 45), new BitfieldOffset(true, 1));
- var incr2 = new BitfieldIncrby(new BitfieldEncoding(Signedness.Signed, 45), new BitfieldOffset(true, 1), 1, BitfieldOverflowHandling.Fail);
-
- var subcommands = new BitfieldSubCommand[] {set1, get1, incr1, set2, get2, incr2};
- var res = await db.StringBitfieldAsync(key, subcommands);
+ var builder = new BitfieldCommandBuilder()
+ .BitfieldSet(new BitfieldEncoding(Signedness.Unsigned, 3), new BitfieldOffset(false, 5), 7)
+ .BitfieldGet(new BitfieldEncoding(Signedness.Unsigned, 3), new BitfieldOffset(false, 5))
+ .BitfieldIncrby(new BitfieldEncoding(Signedness.Unsigned, 3), new BitfieldOffset(false, 5), -1)
+ .BitfieldSet(new BitfieldEncoding(Signedness.Signed, 45), new BitfieldOffset(true, 1), 17592186044415)
+ .BitfieldGet(new BitfieldEncoding(Signedness.Signed, 45), new BitfieldOffset(true, 1))
+ .BitfieldIncrby(new BitfieldEncoding(Signedness.Signed, 45), new BitfieldOffset(true, 1), 1,
+ BitfieldOverflowHandling.Fail);
+
+ var res = await db.StringBitfieldAsync(key, builder);
Assert.Equal(0, res[0]);
Assert.Equal(7, res[1]);
From 9dae591532defe145d97bf579bea147725128975 Mon Sep 17 00:00:00 2001
From: Nick Craver
Date: Sun, 15 May 2022 21:07:49 -0400
Subject: [PATCH 10/14] Fix spacing
---
tests/StackExchange.Redis.Tests/Bitfield.cs | 2 --
tests/StackExchange.Redis.Tests/Strings.cs | 1 -
2 files changed, 3 deletions(-)
diff --git a/tests/StackExchange.Redis.Tests/Bitfield.cs b/tests/StackExchange.Redis.Tests/Bitfield.cs
index 5a1c9e460..54f0f7c1f 100644
--- a/tests/StackExchange.Redis.Tests/Bitfield.cs
+++ b/tests/StackExchange.Redis.Tests/Bitfield.cs
@@ -12,7 +12,6 @@ public Bitfield(ITestOutputHelper output, SharedConnectionFixture fixture) : bas
[Fact]
public void TestBitfieldHappyPath()
{
-
using var conn = Create(require: RedisFeatures.v3_2_0);
var db = conn.GetDatabase();
RedisKey key = Me();
@@ -44,7 +43,6 @@ public void TestBitfieldHappyPath()
[Fact]
public async Task TestBitfieldHappyPathAsync()
{
-
using var conn = Create(require: RedisFeatures.v3_2_0);
var db = conn.GetDatabase();
RedisKey key = Me();
diff --git a/tests/StackExchange.Redis.Tests/Strings.cs b/tests/StackExchange.Redis.Tests/Strings.cs
index 54dfcce0d..6aee44764 100644
--- a/tests/StackExchange.Redis.Tests/Strings.cs
+++ b/tests/StackExchange.Redis.Tests/Strings.cs
@@ -651,7 +651,6 @@ public async Task HashStringLengthAsync()
Assert.Equal(0, await resNonExistingAsync);
}
-
[Fact]
public void HashStringLength()
{
From 7c6f62f34d2788027a3ab07c959b35bf5d4a0790 Mon Sep 17 00:00:00 2001
From: Nick Craver
Date: Sun, 15 May 2022 21:44:41 -0400
Subject: [PATCH 11/14] Simplify a bit, update docs
---
.../APITypes/BitfieldCommandBuilder.cs | 70 +++++++++----------
.../Enums/BitfieldOverflowHandling.cs | 2 +-
src/StackExchange.Redis/Enums/Signedness.cs | 28 --------
.../Interfaces/IDatabase.cs | 51 +++++++-------
.../Interfaces/IDatabaseAsync.cs | 49 +++++++------
src/StackExchange.Redis/PublicAPI.Shipped.txt | 10 +--
src/StackExchange.Redis/RedisDatabase.cs | 12 ++--
tests/StackExchange.Redis.Tests/Bitfield.cs | 22 +++---
8 files changed, 111 insertions(+), 133 deletions(-)
delete mode 100644 src/StackExchange.Redis/Enums/Signedness.cs
diff --git a/src/StackExchange.Redis/APITypes/BitfieldCommandBuilder.cs b/src/StackExchange.Redis/APITypes/BitfieldCommandBuilder.cs
index 4c7e14697..660b2387d 100644
--- a/src/StackExchange.Redis/APITypes/BitfieldCommandBuilder.cs
+++ b/src/StackExchange.Redis/APITypes/BitfieldCommandBuilder.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
+using System.Collections.Generic;
namespace StackExchange.Redis;
@@ -17,7 +15,7 @@ public class BitfieldCommandBuilder
///
/// The encoding for the subcommand.
/// The offset into the bitfield for the subcommand.
- public BitfieldCommandBuilder BitfieldGet(BitfieldEncoding encoding, BitfieldOffset offset)
+ public BitfieldCommandBuilder Get(BitfieldEncoding encoding, BitfieldOffset offset)
{
_eligibleForReadOnly = true;
_args.AddLast(RedisLiterals.GET);
@@ -32,7 +30,7 @@ public BitfieldCommandBuilder BitfieldGet(BitfieldEncoding encoding, BitfieldOff
/// The encoding of the subcommand.
/// The offset of the subcommand.
/// The value to set.
- public BitfieldCommandBuilder BitfieldSet(BitfieldEncoding encoding, BitfieldOffset offset, long value)
+ public BitfieldCommandBuilder Set(BitfieldEncoding encoding, BitfieldOffset offset, long value)
{
_eligibleForReadOnly = false;
_args.AddLast(RedisLiterals.SET);
@@ -49,7 +47,7 @@ public BitfieldCommandBuilder BitfieldSet(BitfieldEncoding encoding, BitfieldOff
/// The offset into the bitfield to increment.
/// The value to increment by.
/// How overflows will be handled when incrementing.
- public BitfieldCommandBuilder BitfieldIncrby(BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap)
+ public BitfieldCommandBuilder Incrby(BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap)
{
_eligibleForReadOnly = false;
if (overflowHandling != BitfieldOverflowHandling.Wrap)
@@ -97,63 +95,63 @@ protected override void WriteImpl(PhysicalConnection physical)
}
///
-/// An offset into a bitfield. This is either a literal offset (number of bits from the beginning of the bitfield) or an
-/// encoding based offset, based off the encoding of the sub-command.
+/// The encoding that a sub-command should use. This is either a signed or unsigned integer of a specified length.
///
-public readonly struct BitfieldOffset
+public readonly struct BitfieldEncoding
{
- ///
- /// Returns the BitfieldOffset as a RedisValue
- ///
- internal RedisValue RedisValue => $"{(ByEncoding ? "#" : string.Empty)}{Offset}";
+ internal RedisValue RedisValue => $"{(IsSigned ? 'i' : 'u')}{Size}";
///
- /// Whether or not the BitfieldOffset will work off of the sub-commands integer encoding.
+ /// Whether the integer is signed or not.
///
- public bool ByEncoding { get; }
+ public bool IsSigned { get; }
///
- /// The number of either bits or encoded integers to offset into the bitfield.
+ /// The size of the integer.
///
- public long Offset { get; }
+ public byte Size { get; }
///
- /// Initializes a bitfield offset
+ /// Initializes the BitfieldEncoding.
///
- /// Whether or not the BitfieldOffset will work off of the sub-commands integer encoding.
- /// The number of either bits or encoded integers to offset into the bitfield.
- public BitfieldOffset(bool byEncoding, long offset)
+ /// Whether the encoding is signed.
+ /// The size of the integer.
+ public BitfieldEncoding(bool isSigned, byte size)
{
- ByEncoding = byEncoding;
- Offset = offset;
+ IsSigned = isSigned;
+ Size = size;
}
}
///
-/// The encoding that a sub-command should use. This is either a signed or unsigned integer of a specified length.
+/// An offset into a bitfield. This is either a literal offset (number of bits from the beginning of the bitfield) or an
+/// encoding based offset, based off the encoding of the sub-command.
///
-public readonly struct BitfieldEncoding
+public readonly struct BitfieldOffset
{
- internal RedisValue RedisValue => $"{Signedness.SignChar()}{Size}";
+ ///
+ /// Returns the BitfieldOffset as a RedisValue.
+ ///
+ internal RedisValue RedisValue => $"{(ByEncoding ? "#" : string.Empty)}{Offset}";
///
- /// The signedness of the integer.
+ /// Whether or not the BitfieldOffset will work off of the sub-commands integer encoding.
///
- public Signedness Signedness { get; }
+ public bool ByEncoding { get; }
///
- /// The size of the integer.
+ /// The number of either bits or encoded integers to offset into the bitfield.
///
- public byte Size { get; }
+ public long Offset { get; }
///
- /// Initializes the BitfieldEncoding.
+ /// Initializes a bitfield offset
///
- /// The encoding's
- /// The size of the integer.
- public BitfieldEncoding(Signedness signedness, byte size)
+ /// Whether or not the BitfieldOffset will work off of the sub-commands integer encoding.
+ /// The number of either bits or encoded integers to offset into the bitfield.
+ public BitfieldOffset(bool byEncoding, long offset)
{
- Signedness = signedness;
- Size = size;
+ ByEncoding = byEncoding;
+ Offset = offset;
}
}
diff --git a/src/StackExchange.Redis/Enums/BitfieldOverflowHandling.cs b/src/StackExchange.Redis/Enums/BitfieldOverflowHandling.cs
index 061b0e025..df9275f34 100644
--- a/src/StackExchange.Redis/Enums/BitfieldOverflowHandling.cs
+++ b/src/StackExchange.Redis/Enums/BitfieldOverflowHandling.cs
@@ -18,7 +18,7 @@ public enum BitfieldOverflowHandling
///
/// If an overflow is encountered, associated subcommand fails, and the result will be NULL.
///
- Fail
+ Fail,
}
internal static class BitfieldOverflowHandlingExtensions
diff --git a/src/StackExchange.Redis/Enums/Signedness.cs b/src/StackExchange.Redis/Enums/Signedness.cs
deleted file mode 100644
index d81a4a16b..000000000
--- a/src/StackExchange.Redis/Enums/Signedness.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-
-namespace StackExchange.Redis;
-
-///
-/// Represents an integers signedness
-///
-public enum Signedness
-{
- ///
- /// An integer with no sign bit.
- ///
- Unsigned,
- ///
- /// An integer with a sign bit.
- ///
- Signed
-}
-
-internal static class SignednessExtensions
-{
- internal static char SignChar(this Signedness sign) => sign switch
- {
- Signedness.Signed => 'i',
- Signedness.Unsigned => 'u',
- _ => throw new ArgumentOutOfRangeException(nameof(sign))
- };
-}
diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs
index 08e9081a3..d1280d712 100644
--- a/src/StackExchange.Redis/Interfaces/IDatabase.cs
+++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs
@@ -2548,56 +2548,59 @@ IEnumerable SortedSetScan(RedisKey key,
long StringBitCount(RedisKey key, long start = 0, long end = -1, StringIndexType indexType = StringIndexType.Byte, CommandFlags flags = CommandFlags.None);
///
- /// Pulls a single number out of a bitfield of the provided at the given offset. Will execute a BITFIELD_RO if possible.
+ /// Executes a set of Bitfield subcommands as constructed by the against the bitfield at the provided .
+ /// Will run as a BITFIELD_RO if all operations are read-only and the command is available.
+ ///
+ /// The key of the string.
+ /// The subcommands to execute against the bitfield.
+ /// The flags to use for this operation.
+ /// An array of numbers corresponding to the result of each sub-command. For increment subcommands, these can be null.
+ ///
+ /// ,
+ ///
+ ///
+ long?[] StringBitfield(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None);
+
+ ///
+ /// Pulls a single number out of a bitfield of the provided at the given offset.
+ /// Will execute a BITFIELD_RO if possible.
///
/// The key for the string.
/// The encoding of the number.
/// The offset into the bitfield to pull the number from.
- /// The Commands for the operation.
+ /// The flags to use for this operation.
/// The number of the given at the provided .
- ///
- ///
+ ///
+ /// ,
+ ///
+ ///
long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None);
///
- /// Sets a single number number in a bitfield at the provided to the provided, in the given .
+ /// Sets a single number in a bitfield at the provided to the provided, in the given .
///
/// The key for the string.
/// The encoding of the number.
/// The offset into the bitfield to pull the number from.
/// the value to set the bitfield to.
- /// The Commands for the operation.
- /// The previous value as am at the provided .
+ /// The flags to use for this operation.
+ /// The previous value as an at the provided .
///
long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None);
-
///
- /// increments a single number number in a bitfield at the provided in the provided by the given .
+ /// Increments a single number in a bitfield at the provided in the provided by the given .
///
/// The key for the string.
/// The encoding of the number.
/// The offset into the bitfield to pull the number from.
/// the value to increment the bitfield by.
/// The way integer overflows are handled.
- /// The Commands for the operation.
- /// The new value of the given at the provided after the incrby is applied, represented as an . Returns if the operation fails.
+ /// The flags to use for this operation.
+ /// The new value of the given at the provided after the INCRBY is applied, represented as an . Returns if the operation fails.
///
long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None);
-
- ///
- /// Executes a set of Bitfield subcommands as constructed by the against the bitfield at the provided .
- /// Will run as a BITFIELD_RO if all operations are read-only and the command is available.
- ///
- /// The key of the string.
- /// The subcommands to execute against the bitfield.
- /// The flags for this operation.
- /// An array of numbers corresponding to the result of each sub-command. For increment subcommands, these can be null.
- ///
- ///
- long?[] StringBitfield(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None);
-
///
/// Perform a bitwise operation between multiple keys (containing string values) and store the result in the destination key.
/// The BITOP command supports four bitwise operations; note that NOT is a unary operator: the second key should be omitted in this case
diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
index 65be7fd5c..eb14d4691 100644
--- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
+++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
@@ -2500,54 +2500,59 @@ IAsyncEnumerable SortedSetScanAsync(RedisKey key,
Task StringBitCountAsync(RedisKey key, long start = 0, long end = -1, StringIndexType indexType = StringIndexType.Byte, CommandFlags flags = CommandFlags.None);
///
- /// Pulls a single number out of a bitfield of the provided at the given offset. Will execute a BITFIELD_RO if possible.
+ /// Executes a set of Bitfield subcommands as constructed by the against the bitfield at the provided .
+ /// Will run as a BITFIELD_RO if all operations are read-only and the command is available.
+ ///
+ /// The key of the string.
+ /// The subcommands to execute against the bitfield.
+ /// The flags to use for this operation.
+ /// An array of numbers corresponding to the result of each sub-command. For increment subcommands, these can be null.
+ ///
+ /// ,
+ ///
+ ///
+ Task StringBitfieldAsync(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None);
+
+ ///
+ /// Pulls a single number out of a bitfield of the provided at the given offset.
+ /// Will execute a BITFIELD_RO if possible.
///
/// The key for the string.
/// The encoding of the number.
/// The offset into the bitfield to pull the number from.
- /// The Commands for the operation.
+ /// The flags to use for this operation.
/// The number of the given at the provided .
- ///
- ///
+ ///
+ /// ,
+ ///
+ ///
Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None);
///
- /// Sets a single number number in a bitfield at the provided to the provided, in the given .
+ /// Sets a single number in a bitfield at the provided to the provided, in the given .
///
/// The key for the string.
/// The encoding of the number.
/// The offset into the bitfield to pull the number from.
/// the value to set the bitfield to.
- /// The Commands for the operation.
- /// The previous value as am at the provided .
+ /// The flags to use for this operation.
+ /// The previous value as an at the provided .
///
Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None);
///
- /// Increments a single number number in a bitfield at the provided as if it were in the given by the given .
+ /// Increments a single number in a bitfield at the provided in the provided by the given .
///
/// The key for the string.
/// The encoding of the number.
/// The offset into the bitfield to pull the number from.
/// the value to increment the bitfield by.
/// The way integer overflows are handled.
- /// The Commands for the operation.
- /// The new value of the given at the provided after the incrby is applied, represented as an . Returns if the operation fails.
+ /// The flags to use for this operation.
+ /// The new value of the given at the provided after the INCRBY is applied, represented as an . Returns if the operation fails.
///
Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None);
- ///
- /// Executes a set of Bitfield subcommands as constructed by the against the bitfield at the provided .
- /// Will run as a BITFIELD_RO if all operations are read-only and the command is available.
- ///
- /// The key of the string.
- /// The subcommands to execute against the bitfield.
- /// The flags for this operation.
- /// An array of numbers corresponding to the result of each sub-command. For increment subcommands, these can be null.
- ///
- ///
- Task StringBitfieldAsync(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None);
-
///
/// Perform a bitwise operation between multiple keys (containing string values) and store the result in the destination key.
/// The BITOP command supports four bitwise operations; note that NOT is a unary operator: the second key should be omitted in this case
diff --git a/src/StackExchange.Redis/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI.Shipped.txt
index cea26bd70..012dfbd9a 100644
--- a/src/StackExchange.Redis/PublicAPI.Shipped.txt
+++ b/src/StackExchange.Redis/PublicAPI.Shipped.txt
@@ -68,13 +68,13 @@ StackExchange.Redis.BacklogPolicy.QueueWhileDisconnected.get -> bool
StackExchange.Redis.BacklogPolicy.QueueWhileDisconnected.init -> void
StackExchange.Redis.BitfieldCommandBuilder
StackExchange.Redis.BitfieldCommandBuilder.BitfieldCommandBuilder() -> void
-StackExchange.Redis.BitfieldCommandBuilder.BitfieldGet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset) -> StackExchange.Redis.BitfieldCommandBuilder!
-StackExchange.Redis.BitfieldCommandBuilder.BitfieldIncrby(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap) -> StackExchange.Redis.BitfieldCommandBuilder!
-StackExchange.Redis.BitfieldCommandBuilder.BitfieldSet(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value) -> StackExchange.Redis.BitfieldCommandBuilder!
+StackExchange.Redis.BitfieldCommandBuilder.Get(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset) -> StackExchange.Redis.BitfieldCommandBuilder!
+StackExchange.Redis.BitfieldCommandBuilder.Incrby(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap) -> StackExchange.Redis.BitfieldCommandBuilder!
+StackExchange.Redis.BitfieldCommandBuilder.Set(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value) -> StackExchange.Redis.BitfieldCommandBuilder!
StackExchange.Redis.BitfieldEncoding
StackExchange.Redis.BitfieldEncoding.BitfieldEncoding() -> void
-StackExchange.Redis.BitfieldEncoding.BitfieldEncoding(StackExchange.Redis.Signedness signedness, byte size) -> void
-StackExchange.Redis.BitfieldEncoding.Signedness.get -> StackExchange.Redis.Signedness
+StackExchange.Redis.BitfieldEncoding.BitfieldEncoding(bool isSigned, byte size) -> void
+StackExchange.Redis.BitfieldEncoding.IsSigned.get -> bool
StackExchange.Redis.BitfieldEncoding.Size.get -> byte
StackExchange.Redis.BitfieldOffset
StackExchange.Redis.BitfieldOffset.BitfieldOffset() -> void
diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs
index 1996694f2..3d36781a5 100644
--- a/src/StackExchange.Redis/RedisDatabase.cs
+++ b/src/StackExchange.Redis/RedisDatabase.cs
@@ -2866,37 +2866,37 @@ public Task StringBitCountAsync(RedisKey key, long start = 0, long end = -
public long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None)
{
- var msg = new BitfieldCommandBuilder().BitfieldGet(encoding, offset).Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = new BitfieldCommandBuilder().Get(encoding, offset).Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteSync(msg, ResultProcessor.Int64, server);
}
public Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None)
{
- var msg = new BitfieldCommandBuilder().BitfieldGet(encoding, offset).Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = new BitfieldCommandBuilder().Get(encoding, offset).Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteAsync(msg, ResultProcessor.Int64, server);
}
public long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None)
{
- var msg = new BitfieldCommandBuilder().BitfieldSet(encoding, offset, value).Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = new BitfieldCommandBuilder().Set(encoding, offset, value).Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteSync(msg, ResultProcessor.Int64, server);
}
public Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None)
{
- var msg = new BitfieldCommandBuilder().BitfieldSet(encoding, offset, value).Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = new BitfieldCommandBuilder().Set(encoding, offset, value).Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteAsync(msg, ResultProcessor.Int64, server);
}
public long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None)
{
- var msg = new BitfieldCommandBuilder().BitfieldIncrby(encoding, offset, increment, overflowHandling).Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = new BitfieldCommandBuilder().Incrby(encoding, offset, increment, overflowHandling).Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteSync(msg, ResultProcessor.NullableInt64, server);
}
public Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None)
{
- var msg = new BitfieldCommandBuilder().BitfieldIncrby(encoding, offset, increment, overflowHandling).Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = new BitfieldCommandBuilder().Incrby(encoding, offset, increment, overflowHandling).Build(Database, key, flags, this, out ServerEndPoint? server);
return ExecuteAsync(msg, ResultProcessor.NullableInt64, server);
}
diff --git a/tests/StackExchange.Redis.Tests/Bitfield.cs b/tests/StackExchange.Redis.Tests/Bitfield.cs
index 54f0f7c1f..5cada2413 100644
--- a/tests/StackExchange.Redis.Tests/Bitfield.cs
+++ b/tests/StackExchange.Redis.Tests/Bitfield.cs
@@ -17,7 +17,7 @@ public void TestBitfieldHappyPath()
RedisKey key = Me();
db.KeyDelete(key);
- var encoding = new BitfieldEncoding(Signedness.Signed, 10);
+ var encoding = new BitfieldEncoding(isSigned: true, 10);
var offset = new BitfieldOffset(true, 1);
// should be the old value
@@ -28,7 +28,7 @@ public void TestBitfieldHappyPath()
Assert.Equal(-255, getResult);
Assert.Equal(-265, incrementResult);
- encoding = new BitfieldEncoding(Signedness.Unsigned, 18);
+ encoding = new BitfieldEncoding(isSigned: false, 18);
offset = new BitfieldOffset(false, 22);
setResult = db.StringBitfieldSet(key, encoding, offset, 262123);
@@ -48,7 +48,7 @@ public async Task TestBitfieldHappyPathAsync()
RedisKey key = Me();
db.KeyDelete(key);
- var encoding = new BitfieldEncoding(Signedness.Signed, 10);
+ var encoding = new BitfieldEncoding(isSigned: true, 10);
var offset = new BitfieldOffset(true, 1);
// should be the old value
@@ -59,7 +59,7 @@ public async Task TestBitfieldHappyPathAsync()
Assert.Equal(-255, getResult);
Assert.Equal(-265, incrementResult);
- encoding = new BitfieldEncoding(Signedness.Unsigned, 18);
+ encoding = new BitfieldEncoding(isSigned: false, 18);
offset = new BitfieldOffset(false, 22);
setResult = await db.StringBitfieldSetAsync(key, encoding, offset, 262123);
@@ -80,12 +80,12 @@ public async Task TestBitfieldMulti()
db.KeyDelete(key);
var builder = new BitfieldCommandBuilder()
- .BitfieldSet(new BitfieldEncoding(Signedness.Unsigned, 3), new BitfieldOffset(false, 5), 7)
- .BitfieldGet(new BitfieldEncoding(Signedness.Unsigned, 3), new BitfieldOffset(false, 5))
- .BitfieldIncrby(new BitfieldEncoding(Signedness.Unsigned, 3), new BitfieldOffset(false, 5), -1)
- .BitfieldSet(new BitfieldEncoding(Signedness.Signed, 45), new BitfieldOffset(true, 1), 17592186044415)
- .BitfieldGet(new BitfieldEncoding(Signedness.Signed, 45), new BitfieldOffset(true, 1))
- .BitfieldIncrby(new BitfieldEncoding(Signedness.Signed, 45), new BitfieldOffset(true, 1), 1,
+ .Set(new BitfieldEncoding(isSigned: false, 3), new BitfieldOffset(false, 5), 7)
+ .Get(new BitfieldEncoding(isSigned: false, 3), new BitfieldOffset(false, 5))
+ .Incrby(new BitfieldEncoding(isSigned: false, 3), new BitfieldOffset(false, 5), -1)
+ .Set(new BitfieldEncoding(isSigned: true, 45), new BitfieldOffset(true, 1), 17592186044415)
+ .Get(new BitfieldEncoding(isSigned: true, 45), new BitfieldOffset(true, 1))
+ .Incrby(new BitfieldEncoding(isSigned: true, 45), new BitfieldOffset(true, 1), 1,
BitfieldOverflowHandling.Fail);
var res = await db.StringBitfieldAsync(key, builder);
@@ -106,7 +106,7 @@ public async Task TestOverflows()
RedisKey key = Me();
db.KeyDelete(key);
- var encoding = new BitfieldEncoding(Signedness.Signed, 3);
+ var encoding = new BitfieldEncoding(isSigned: true, 3);
var offset = new BitfieldOffset(true, 3);
await db.StringBitfieldSetAsync(key, encoding, offset, 3);
From 5f072907195489b56e819df68fef59cae557774b Mon Sep 17 00:00:00 2001
From: Nick Craver
Date: Sun, 15 May 2022 22:40:11 -0400
Subject: [PATCH 12/14] Save all the files dammit
---
src/StackExchange.Redis/PublicAPI.Shipped.txt | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/StackExchange.Redis/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI.Shipped.txt
index 012dfbd9a..bcf2de82d 100644
--- a/src/StackExchange.Redis/PublicAPI.Shipped.txt
+++ b/src/StackExchange.Redis/PublicAPI.Shipped.txt
@@ -1419,9 +1419,6 @@ StackExchange.Redis.ShutdownMode
StackExchange.Redis.ShutdownMode.Always = 2 -> StackExchange.Redis.ShutdownMode
StackExchange.Redis.ShutdownMode.Default = 0 -> StackExchange.Redis.ShutdownMode
StackExchange.Redis.ShutdownMode.Never = 1 -> StackExchange.Redis.ShutdownMode
-StackExchange.Redis.Signedness
-StackExchange.Redis.Signedness.Signed = 1 -> StackExchange.Redis.Signedness
-StackExchange.Redis.Signedness.Unsigned = 0 -> StackExchange.Redis.Signedness
StackExchange.Redis.SlotRange
StackExchange.Redis.SlotRange.CompareTo(StackExchange.Redis.SlotRange other) -> int
StackExchange.Redis.SlotRange.Equals(StackExchange.Redis.SlotRange other) -> bool
From 1392d2018e0a21ea445746beadb7a390c0246689 Mon Sep 17 00:00:00 2001
From: slorello89
Date: Fri, 1 Dec 2023 09:34:43 -0500
Subject: [PATCH 13/14] api updates per marcs comments
---
.../APITypes/BitfieldCommandBuilder.cs | 157 ------------
.../APITypes/BitfieldOperation.cs | 224 ++++++++++++++++++
.../Interfaces/IDatabase.cs | 42 ++--
.../Interfaces/IDatabaseAsync.cs | 44 ++--
.../KeyspaceIsolation/KeyPrefixed.cs | 19 +-
.../KeyspaceIsolation/KeyPrefixedDatabase.cs | 18 +-
.../PublicAPI/PublicAPI.Shipped.txt | 23 --
.../PublicAPI/PublicAPI.Unshipped.txt | 17 ++
src/StackExchange.Redis/RedisDatabase.cs | 32 +--
tests/StackExchange.Redis.Tests/Bitfield.cs | 101 +++++---
10 files changed, 388 insertions(+), 289 deletions(-)
delete mode 100644 src/StackExchange.Redis/APITypes/BitfieldCommandBuilder.cs
create mode 100644 src/StackExchange.Redis/APITypes/BitfieldOperation.cs
diff --git a/src/StackExchange.Redis/APITypes/BitfieldCommandBuilder.cs b/src/StackExchange.Redis/APITypes/BitfieldCommandBuilder.cs
deleted file mode 100644
index 1b6f2dfc0..000000000
--- a/src/StackExchange.Redis/APITypes/BitfieldCommandBuilder.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-using System.Collections.Generic;
-
-namespace StackExchange.Redis;
-
-///
-/// Builder for bitfield commands that take multiple sub-commands.
-///
-public class BitfieldCommandBuilder
-{
- private readonly LinkedList _args = new LinkedList();
- private bool _eligibleForReadOnly;
-
- ///
- /// Builds a subcommand for a Bitfield GET, which returns the number stored in the specified offset of a bitfield at the given encoding.
- ///
- /// The encoding for the subcommand.
- /// The offset into the bitfield for the subcommand.
- public BitfieldCommandBuilder Get(BitfieldEncoding encoding, BitfieldOffset offset)
- {
- _eligibleForReadOnly = true;
- _args.AddLast(RedisLiterals.GET);
- _args.AddLast(encoding.RedisValue);
- _args.AddLast(offset.RedisValue);
- return this;
- }
-
- ///
- /// Builds a Bitfield subcommand which SETs the specified range of bits to the specified value.
- ///
- /// The encoding of the subcommand.
- /// The offset of the subcommand.
- /// The value to set.
- public BitfieldCommandBuilder Set(BitfieldEncoding encoding, BitfieldOffset offset, long value)
- {
- _eligibleForReadOnly = false;
- _args.AddLast(RedisLiterals.SET);
- _args.AddLast(encoding.RedisValue);
- _args.AddLast(offset.RedisValue);
- _args.AddLast(value);
- return this;
- }
-
- ///
- /// Builds a subcommand for Bitfield INCRBY, which increments the number at the specified range of bits by the provided value
- ///
- /// The number's encoding.
- /// The offset into the bitfield to increment.
- /// The value to increment by.
- /// How overflows will be handled when incrementing.
- public BitfieldCommandBuilder Incrby(BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap)
- {
- _eligibleForReadOnly = false;
- if (overflowHandling != BitfieldOverflowHandling.Wrap)
- {
- _args.AddLast(RedisLiterals.OVERFLOW);
- _args.AddLast(overflowHandling.AsRedisValue());
- }
-
- _args.AddLast(RedisLiterals.INCRBY);
- _args.AddLast(encoding.RedisValue);
- _args.AddLast(offset.RedisValue);
- _args.AddLast(increment);
- return this;
- }
-
- internal BitfieldCommandMessage Build(int db, RedisKey key, CommandFlags flags, RedisBase redisBase, out ServerEndPoint? server)
- {
- var features = redisBase.GetFeatures(key, flags, _eligibleForReadOnly ? RedisCommand.BITFIELD_RO : RedisCommand.BITFIELD, out server);
- var command = _eligibleForReadOnly && features.ReadOnlyBitfield ? RedisCommand.BITFIELD_RO : RedisCommand.BITFIELD;
- return new BitfieldCommandMessage(db, flags, key, command, _args);
- }
-}
-
-internal class BitfieldCommandMessage : Message
-{
- private readonly LinkedList _args;
- private readonly RedisKey _key;
- public BitfieldCommandMessage(int db, CommandFlags flags, RedisKey key, RedisCommand command, LinkedList args) : base(db, flags, command)
- {
- _key = key;
- _args = args;
- }
-
- public override int ArgCount => 1 + _args.Count;
-
- protected override void WriteImpl(PhysicalConnection physical)
- {
- physical.WriteHeader(Command, ArgCount);
- physical.Write(_key);
- foreach (var arg in _args)
- {
- physical.WriteBulkString(arg);
- }
- }
-}
-
-///
-/// The encoding that a sub-command should use. This is either a signed or unsigned integer of a specified length.
-///
-public readonly struct BitfieldEncoding
-{
- internal RedisValue RedisValue => $"{(IsSigned ? 'i' : 'u')}{Size}";
-
- ///
- /// Whether the integer is signed or not.
- ///
- public bool IsSigned { get; }
-
- ///
- /// The size of the integer.
- ///
- public byte Size { get; }
-
- ///
- /// Initializes the BitfieldEncoding.
- ///
- /// Whether the encoding is signed.
- /// The size of the integer.
- public BitfieldEncoding(bool isSigned, byte size)
- {
- IsSigned = isSigned;
- Size = size;
- }
-}
-
-///
-/// An offset into a bitfield. This is either a literal offset (number of bits from the beginning of the bitfield) or an
-/// encoding based offset, based off the encoding of the sub-command.
-///
-public readonly struct BitfieldOffset
-{
- ///
- /// Returns the BitfieldOffset as a RedisValue.
- ///
- internal RedisValue RedisValue => $"{(ByEncoding ? "#" : string.Empty)}{Offset}";
-
- ///
- /// Whether or not the BitfieldOffset will work off of the sub-commands integer encoding.
- ///
- public bool ByEncoding { get; }
-
- ///
- /// The number of either bits or encoded integers to offset into the bitfield.
- ///
- public long Offset { get; }
-
- ///
- /// Initializes a bitfield offset
- ///
- /// Whether or not the BitfieldOffset will work off of the sub-commands integer encoding.
- /// The number of either bits or encoded integers to offset into the bitfield.
- public BitfieldOffset(bool byEncoding, long offset)
- {
- ByEncoding = byEncoding;
- Offset = offset;
- }
-}
diff --git a/src/StackExchange.Redis/APITypes/BitfieldOperation.cs b/src/StackExchange.Redis/APITypes/BitfieldOperation.cs
new file mode 100644
index 000000000..311502857
--- /dev/null
+++ b/src/StackExchange.Redis/APITypes/BitfieldOperation.cs
@@ -0,0 +1,224 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace StackExchange.Redis;
+
+///
+/// Represents a single Bitfield Operation.
+///
+public struct BitfieldOperation
+{
+ private static string CreateOffset(bool offsetByBit, long offset) => $"{(offsetByBit ? string.Empty : "#")}{offset}";
+ private static readonly string[] Encodings = Enumerable.Range(0, 127).Select(x => // 0?
+ {
+ var size = x % 64;
+ var signedness = x < 65 ? "i" : "u";
+ return $"{signedness}{size}";
+ }).ToArray();
+
+ private static RedisValue CreateEncoding(bool unsigned, byte size)
+ {
+ if (size == 0)
+ {
+ throw new ArgumentException("Invalid encoding, size must be non-zero", nameof(size));
+ }
+
+ if (unsigned && size > 63)
+ {
+ throw new ArgumentException(
+ $"Invalid Encoding, unsigned bitfield operations support a maximum size of 63, provided size: {size}", nameof(size));
+ }
+
+ if (size > 64)
+ {
+ throw new ArgumentException(
+ $"Invalid Encoding, signed bitfield operations support a maximum size of 64, provided size: {size}", nameof(size));
+ }
+
+ return Encodings[size + (!unsigned ? 0 : 64)];
+ }
+
+ internal string Offset;
+ internal long? Value;
+ internal BitFieldSubCommand SubCommand;
+ internal RedisValue Encoding;
+ internal BitfieldOverflowHandling? BitfieldOverflowHandling;
+
+ ///
+ /// Creates a Get Bitfield Subcommand struct to retrieve a single integer from the bitfield.
+ ///
+ /// The offset into the bitfield to address.
+ /// The width of the encoding to interpret the bitfield width.
+ /// Whether or not to offset into the bitfield by bits vs encoding.
+ /// Whether or not to interpret the number gotten as an unsigned integer.
+ ///
+ public static BitfieldOperation Get(long offset, byte width, bool offsetByBit = true, bool unsigned = false)
+ {
+ var offsetValue = CreateOffset(offsetByBit, offset);
+ return new BitfieldOperation
+ {
+ Offset = offsetValue,
+ Value = null,
+ SubCommand = BitFieldSubCommand.Get,
+ Encoding = CreateEncoding(unsigned, width)
+ };
+ }
+
+ ///
+ /// Creates a Set Bitfield SubCommand to set a single integer from the bitfield.
+ ///
+ /// The offset into the bitfield to address.
+ /// The width of the encoding to interpret the bitfield width.
+ /// The value to set the addressed bits to.
+ /// Whether or not to offset into the bitfield by bits vs encoding.
+ /// Whether or not to interpret the number gotten as an unsigned integer.
+ ///
+ public static BitfieldOperation Set(long offset, byte width, long value, bool offsetByBit = true, bool unsigned = false)
+ {
+ var offsetValue = CreateOffset(offsetByBit, offset);
+ return new BitfieldOperation
+ {
+ Offset = offsetValue,
+ Value = value,
+ SubCommand = BitFieldSubCommand.Set,
+ Encoding = CreateEncoding(unsigned, width)
+ };
+ }
+
+ ///
+ /// Creates an Increment Bitfield SubCommand to increment a single integer from the bitfield.
+ ///
+ /// The offset into the bitfield to address.
+ /// The width of the encoding to interpret the bitfield width.
+ /// The value to set the addressed bits to.
+ /// Whether or not to offset into the bitfield by bits vs encoding.
+ /// Whether or not to interpret the number gotten as an unsigned integer.
+ /// How to handle overflows.
+ ///
+ public static BitfieldOperation Increment(long offset, byte width, long increment, bool offsetByBit = true, bool unsigned = false, BitfieldOverflowHandling overflowHandling = Redis.BitfieldOverflowHandling.Wrap)
+ {
+ var offsetValue = CreateOffset(offsetByBit, offset);
+ return new BitfieldOperation
+ {
+ Offset = offsetValue,
+ Value = increment,
+ SubCommand = BitFieldSubCommand.Increment,
+ Encoding = CreateEncoding(unsigned, width),
+ BitfieldOverflowHandling = overflowHandling
+ };
+ }
+
+ internal IEnumerable EnumerateArgs()
+ {
+ if (SubCommand != BitFieldSubCommand.Get)
+ {
+ if (BitfieldOverflowHandling is not null && BitfieldOverflowHandling != Redis.BitfieldOverflowHandling.Wrap)
+ {
+ yield return RedisLiterals.OVERFLOW;
+ yield return BitfieldOverflowHandling.Value.AsRedisValue();
+ }
+ }
+
+ yield return SubCommand.AsRedisValue();
+ yield return Encoding;
+ yield return Offset;
+ if (SubCommand != BitFieldSubCommand.Get)
+ {
+ if (Value is null)
+ {
+ throw new ArgumentNullException($"Value must not be null for {SubCommand.AsRedisValue()} commands");
+ }
+
+ yield return Value;
+ }
+ }
+
+ internal int NumArgs()
+ {
+ var numArgs = 3;
+ if (SubCommand != BitFieldSubCommand.Get)
+ {
+ numArgs += BitfieldOverflowHandling is not null && BitfieldOverflowHandling != Redis.BitfieldOverflowHandling.Wrap ? 3 : 1;
+ }
+
+ return numArgs;
+ }
+}
+
+internal static class BitfieldOperationExtensions
+{
+ internal static BitfieldCommandMessage BuildMessage(this BitfieldOperation[] subCommands, int db, RedisKey key,
+ CommandFlags flags, RedisBase redisBase, out ServerEndPoint? server)
+ {
+ var eligibleForReadOnly = subCommands.All(x => x.SubCommand == BitFieldSubCommand.Get);
+ var features = redisBase.GetFeatures(key, flags, eligibleForReadOnly ? RedisCommand.BITFIELD_RO : RedisCommand.BITFIELD, out server);
+ var command = eligibleForReadOnly && features.ReadOnlyBitfield ? RedisCommand.BITFIELD_RO : RedisCommand.BITFIELD;
+ return new BitfieldCommandMessage(db, flags, key, command, subCommands.SelectMany(x=>x.EnumerateArgs()).ToArray());
+ }
+
+ internal static BitfieldCommandMessage BuildMessage(this BitfieldOperation subCommand, int db, RedisKey key,
+ CommandFlags flags, RedisBase redisBase, out ServerEndPoint? server)
+ {
+ var eligibleForReadOnly = subCommand.SubCommand == BitFieldSubCommand.Get;
+ var features = redisBase.GetFeatures(key, flags, eligibleForReadOnly ? RedisCommand.BITFIELD_RO : RedisCommand.BITFIELD, out server);
+ var command = eligibleForReadOnly && features.ReadOnlyBitfield ? RedisCommand.BITFIELD_RO : RedisCommand.BITFIELD;
+ return new BitfieldCommandMessage(db, flags, key, command, subCommand.EnumerateArgs().ToArray());
+ }
+}
+
+///
+/// Bitfield subcommands.
+///
+public enum BitFieldSubCommand
+{
+ ///
+ /// Subcommand to get the bitfield value.
+ ///
+ Get,
+
+ ///
+ /// Subcommand to set the bitfield value.
+ ///
+ Set,
+
+ ///
+ /// Subcommand to increment the bitfield value
+ ///
+ Increment
+}
+
+internal static class BitfieldSubCommandExtensions
+{
+ internal static RedisValue AsRedisValue(this BitFieldSubCommand subCommand) =>
+ subCommand switch
+ {
+ BitFieldSubCommand.Get => RedisLiterals.GET,
+ BitFieldSubCommand.Set => RedisLiterals.SET,
+ BitFieldSubCommand.Increment => RedisLiterals.INCRBY,
+ _ => throw new ArgumentOutOfRangeException(nameof(subCommand))
+ };
+}
+
+internal class BitfieldCommandMessage : Message
+{
+ private readonly IEnumerable _args;
+ private readonly RedisKey _key;
+ public BitfieldCommandMessage(int db, CommandFlags flags, RedisKey key, RedisCommand command, RedisValue[] args) : base(db, flags, command)
+ {
+ _key = key;
+ _args = args;
+ }
+
+ public override int ArgCount => 1 + _args.Count();
+
+ protected override void WriteImpl(PhysicalConnection physical)
+ {
+ physical.WriteHeader(Command, ArgCount);
+ physical.Write(_key);
+ foreach (var arg in _args)
+ {
+ physical.WriteBulkString(arg);
+ }
+ }
+}
diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs
index 99f8d2f4b..87ccf925e 100644
--- a/src/StackExchange.Redis/Interfaces/IDatabase.cs
+++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs
@@ -2595,58 +2595,64 @@ IEnumerable SortedSetScan(RedisKey key,
long StringBitCount(RedisKey key, long start = 0, long end = -1, StringIndexType indexType = StringIndexType.Byte, CommandFlags flags = CommandFlags.None);
///
- /// Executes a set of Bitfield subcommands as constructed by the against the bitfield at the provided .
+ /// Executes a set of Bitfield subcommands as constructed by the against the bitfield at the provided .
/// Will run as a BITFIELD_RO if all operations are read-only and the command is available.
///
/// The key of the string.
- /// The subcommands to execute against the bitfield.
+ /// The subcommands to execute against the bitfield.
/// The flags to use for this operation.
/// An array of numbers corresponding to the result of each sub-command. For increment subcommands, these can be null.
///
/// ,
///
///
- long?[] StringBitfield(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None);
+ long?[] StringBitfield(RedisKey key, BitfieldOperation[] subCommands, CommandFlags flags = CommandFlags.None);
///
- /// Pulls a single number out of a bitfield of the provided at the given offset.
+ /// Pulls a single number out of a bitfield of the provided encoding at the given offset.
/// Will execute a BITFIELD_RO if possible.
///
/// The key for the string.
- /// The encoding of the number.
/// The offset into the bitfield to pull the number from.
+ /// The width of the encoding to interpret the bitfield width.
+ /// Whether or not to offset into the bitfield by bits vs encoding.
+ /// Whether or not to interpret the number gotten as an unsigned integer.
/// The flags to use for this operation.
- /// The number of the given at the provided .
+ /// The number of the given encoding at the provided .
///
/// ,
///
///
- long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None);
+ long StringBitfieldGet(RedisKey key, long offset, byte width, bool offsetByBit = true, bool unsigned = false, CommandFlags flags = CommandFlags.None);
///
- /// Sets a single number in a bitfield at the provided to the provided, in the given .
+ /// Sets a single number in a bitfield at the provided offset to the provided, in the given encoding.
///
/// The key for the string.
- /// The encoding of the number.
- /// The offset into the bitfield to pull the number from.
- /// the value to set the bitfield to.
+ /// The offset into the bitfield to address.
+ /// The width of the encoding to interpret the bitfield width.
+ /// The value to set the addressed bits to.
+ /// Whether or not to offset into the bitfield by bits vs encoding.
+ /// Whether or not to interpret the number gotten as an unsigned integer.
/// The flags to use for this operation.
/// The previous value as an at the provided .
///
- long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None);
+ long StringBitfieldSet(RedisKey key, long offset, byte width, long value, bool offsetByBit = true, bool unsigned = false, CommandFlags flags = CommandFlags.None);
///
- /// Increments a single number in a bitfield at the provided in the provided by the given .
+ /// Increments a single number in a bitfield at the provided in the provided encoding by the given .
///
/// The key for the string.
- /// The encoding of the number.
- /// The offset into the bitfield to pull the number from.
- /// the value to increment the bitfield by.
- /// The way integer overflows are handled.
+ /// The offset into the bitfield to address.
+ /// The width of the encoding to interpret the bitfield width.
+ /// The value to set the addressed bits to.
+ /// Whether or not to offset into the bitfield by bits vs encoding.
+ /// Whether or not to interpret the number gotten as an unsigned integer.
+ /// How to handle overflows.
/// The flags to use for this operation.
/// The new value of the given at the provided after the INCRBY is applied, represented as an . Returns if the operation fails.
///
- long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None);
+ long? StringBitfieldIncrement(RedisKey key, long offset, byte width, long increment, bool offsetByBit = true, bool unsigned = false, BitfieldOverflowHandling overflowHandling = Redis.BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None);
///
/// Perform a bitwise operation between multiple keys (containing string values) and store the result in the destination key.
diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
index c50f0d4f4..269f40815 100644
--- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
+++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
@@ -2548,58 +2548,64 @@ IAsyncEnumerable SortedSetScanAsync(RedisKey key,
Task StringBitCountAsync(RedisKey key, long start = 0, long end = -1, StringIndexType indexType = StringIndexType.Byte, CommandFlags flags = CommandFlags.None);
///
- /// Executes a set of Bitfield subcommands as constructed by the against the bitfield at the provided .
+ /// Executes a set of Bitfield subcommands as constructed by the against the bitfield at the provided .
/// Will run as a BITFIELD_RO if all operations are read-only and the command is available.
///
/// The key of the string.
- /// The subcommands to execute against the bitfield.
+ /// The subcommands to execute against the bitfield.
/// The flags to use for this operation.
/// An array of numbers corresponding to the result of each sub-command. For increment subcommands, these can be null.
///
/// ,
///
///
- Task StringBitfieldAsync(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None);
+ Task StringBitfieldAsync(RedisKey key, BitfieldOperation[] subCommands, CommandFlags flags = CommandFlags.None);
///
- /// Pulls a single number out of a bitfield of the provided at the given offset.
+ /// Pulls a single number out of a bitfield of the provided encoding at the given offset.
/// Will execute a BITFIELD_RO if possible.
///
/// The key for the string.
- /// The encoding of the number.
- /// The offset into the bitfield to pull the number from.
+ /// The offset into the bitfield to address.
+ /// The width of the encoding to interpret the bitfield width.
+ /// Whether or not to offset into the bitfield by bits vs encoding.
+ /// Whether or not to interpret the number gotten as an unsigned integer.
/// The flags to use for this operation.
- /// The number of the given at the provided .
+ /// The number of the given encoding at the provided .
///
/// ,
///
///
- Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None);
+ Task StringBitfieldGetAsync(RedisKey key, long offset, byte width, bool offsetByBit = true, bool unsigned = false, CommandFlags flags = CommandFlags.None);
///
- /// Sets a single number in a bitfield at the provided to the provided, in the given .
+ /// Sets a single number in a bitfield at the provided to the provided, in the given encoding.
///
/// The key for the string.
- /// The encoding of the number.
- /// The offset into the bitfield to pull the number from.
- /// the value to set the bitfield to.
+ /// The offset into the bitfield to address.
+ /// The width of the encoding to interpret the bitfield width.
+ /// The value to set the addressed bits to.
+ /// Whether or not to offset into the bitfield by bits vs encoding.
+ /// Whether or not to interpret the number gotten as an unsigned integer.
/// The flags to use for this operation.
/// The previous value as an at the provided .
///
- Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None);
+ Task StringBitfieldSetAsync(RedisKey key, long offset, byte width, long value, bool offsetByBit = true, bool unsigned = false, CommandFlags flags = CommandFlags.None);
///
- /// Increments a single number in a bitfield at the provided in the provided by the given .
+ /// Increments a single number in a bitfield at the provided in the provided encoding by the given .
///
/// The key for the string.
- /// The encoding of the number.
- /// The offset into the bitfield to pull the number from.
- /// the value to increment the bitfield by.
- /// The way integer overflows are handled.
+ /// The offset into the bitfield to address.
+ /// The width of the encoding to interpret the bitfield width.
+ /// The value to set the addressed bits to.
+ /// Whether or not to offset into the bitfield by bits vs encoding.
+ /// Whether or not to interpret the number gotten as an unsigned integer.
+ /// How to handle overflows.
/// The flags to use for this operation.
/// The new value of the given at the provided after the INCRBY is applied, represented as an . Returns if the operation fails.
///
- Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None);
+ Task StringBitfieldIncrementAsync(RedisKey key, long offset, byte width, long increment, bool offsetByBit = true, bool unsigned = false, BitfieldOverflowHandling overflowHandling = Redis.BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None);
///
/// Perform a bitwise operation between multiple keys (containing string values) and store the result in the destination key.
diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs
index 19bf83110..70293d7ca 100644
--- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs
+++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs
@@ -630,22 +630,21 @@ public Task StringAppendAsync(RedisKey key, RedisValue value, CommandFlags
public Task StringBitCountAsync(RedisKey key, long start, long end, CommandFlags flags) =>
Inner.StringBitCountAsync(ToInner(key), start, end, flags);
-
+
public Task StringBitCountAsync(RedisKey key, long start = 0, long end = -1, StringIndexType indexType = StringIndexType.Byte, CommandFlags flags = CommandFlags.None) =>
Inner.StringBitCountAsync(ToInner(key), start, end, indexType, flags);
- public Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset,
- CommandFlags flags = CommandFlags.None) =>
- Inner.StringBitfieldGetAsync(ToInner(key), encoding, offset, flags);
+ public Task StringBitfieldGetAsync(RedisKey key, long offset, byte width, bool offsetByBit = true, bool unsigned = false, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldGetAsync(ToInner(key), offset, width, offsetByBit, unsigned, flags);
- public Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None) =>
- Inner.StringBitfieldSetAsync(ToInner(key), encoding, offset, value, flags);
+ public Task StringBitfieldSetAsync(RedisKey key, long offset, byte width, long value, bool offsetByBit = true, bool unsigned = false, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldSetAsync(ToInner(key), offset, width, value, offsetByBit, unsigned, flags);
- public Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None) =>
- Inner.StringBitfieldIncrementAsync(ToInner(key), encoding, offset, increment, overflowHandling, flags);
+ public Task StringBitfieldIncrementAsync(RedisKey key, long offset, byte width, long increment, bool offsetByBit = true, bool unsigned = false, BitfieldOverflowHandling overflowHandling = Redis.BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldIncrementAsync(ToInner(key), offset, width, increment, offsetByBit, unsigned, overflowHandling, flags);
- public Task StringBitfieldAsync(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None) =>
- Inner.StringBitfieldAsync(ToInner(key), builder, flags);
+ public Task StringBitfieldAsync(RedisKey key, BitfieldOperation[] subCommands, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldAsync(ToInner(key), subCommands, flags);
public Task StringBitOperationAsync(Bitwise operation, RedisKey destination, RedisKey[] keys, CommandFlags flags = CommandFlags.None) =>
Inner.StringBitOperationAsync(operation, ToInner(destination), ToInner(keys), flags);
diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs
index 0c9d6c7f7..fe1eec523 100644
--- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs
+++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs
@@ -614,21 +614,21 @@ public long StringAppend(RedisKey key, RedisValue value, CommandFlags flags = Co
public long StringBitCount(RedisKey key, long start, long end, CommandFlags flags) =>
Inner.StringBitCount(ToInner(key), start, end, flags);
-
+
public long StringBitCount(RedisKey key, long start = 0, long end = -1, StringIndexType indexType = StringIndexType.Byte, CommandFlags flags = CommandFlags.None) =>
Inner.StringBitCount(ToInner(key), start, end, indexType, flags);
- public long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None) =>
- Inner.StringBitfieldGet(ToInner(key), encoding, offset, flags);
+ public long StringBitfieldGet(RedisKey key, long offset, byte width, bool offsetByBit = true, bool unsigned = false, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldGet(ToInner(key), offset, width, offsetByBit, unsigned, flags);
- public long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None) =>
- Inner.StringBitfieldSet(ToInner(key), encoding, offset, value, flags);
+ public long StringBitfieldSet(RedisKey key, long offset, byte width, long value, bool offsetByBit = true, bool unsigned = false, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldSet(ToInner(key), offset, width, value, offsetByBit, unsigned, flags);
- public long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None) =>
- Inner.StringBitfieldIncrement(ToInner(key), encoding, offset, increment, overflowHandling, flags);
+ public long? StringBitfieldIncrement(RedisKey key, long offset, byte width, long increment, bool offsetByBit = true, bool unsigned = false, BitfieldOverflowHandling overflowHandling = Redis.BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfieldIncrement(ToInner(key), offset, width, increment, offsetByBit, unsigned, overflowHandling, flags);
- public long?[] StringBitfield(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None) =>
- Inner.StringBitfield(key, builder, flags);
+ public long?[] StringBitfield(RedisKey key, BitfieldOperation[] subCommands, CommandFlags flags = CommandFlags.None) =>
+ Inner.StringBitfield(ToInner(key), subCommands, flags);
public long StringBitOperation(Bitwise operation, RedisKey destination, RedisKey[] keys, CommandFlags flags = CommandFlags.None) =>
Inner.StringBitOperation(operation, ToInner(destination), ToInner(keys), flags);
diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
index ffda71467..871d55de1 100644
--- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
+++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
@@ -65,21 +65,6 @@ StackExchange.Redis.BacklogPolicy.AbortPendingOnConnectionFailure.init -> void
StackExchange.Redis.BacklogPolicy.BacklogPolicy() -> void
StackExchange.Redis.BacklogPolicy.QueueWhileDisconnected.get -> bool
StackExchange.Redis.BacklogPolicy.QueueWhileDisconnected.init -> void
-StackExchange.Redis.BitfieldCommandBuilder
-StackExchange.Redis.BitfieldCommandBuilder.BitfieldCommandBuilder() -> void
-StackExchange.Redis.BitfieldCommandBuilder.Get(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset) -> StackExchange.Redis.BitfieldCommandBuilder!
-StackExchange.Redis.BitfieldCommandBuilder.Incrby(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap) -> StackExchange.Redis.BitfieldCommandBuilder!
-StackExchange.Redis.BitfieldCommandBuilder.Set(StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value) -> StackExchange.Redis.BitfieldCommandBuilder!
-StackExchange.Redis.BitfieldEncoding
-StackExchange.Redis.BitfieldEncoding.BitfieldEncoding() -> void
-StackExchange.Redis.BitfieldEncoding.BitfieldEncoding(bool isSigned, byte size) -> void
-StackExchange.Redis.BitfieldEncoding.IsSigned.get -> bool
-StackExchange.Redis.BitfieldEncoding.Size.get -> byte
-StackExchange.Redis.BitfieldOffset
-StackExchange.Redis.BitfieldOffset.BitfieldOffset() -> void
-StackExchange.Redis.BitfieldOffset.BitfieldOffset(bool byEncoding, long offset) -> void
-StackExchange.Redis.BitfieldOffset.ByEncoding.get -> bool
-StackExchange.Redis.BitfieldOffset.Offset.get -> long
StackExchange.Redis.BitfieldOverflowHandling
StackExchange.Redis.BitfieldOverflowHandling.Fail = 2 -> StackExchange.Redis.BitfieldOverflowHandling
StackExchange.Redis.BitfieldOverflowHandling.Saturate = 1 -> StackExchange.Redis.BitfieldOverflowHandling
@@ -733,10 +718,6 @@ StackExchange.Redis.IDatabase.StreamTrim(StackExchange.Redis.RedisKey key, int m
StackExchange.Redis.IDatabase.StringAppend(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.IDatabase.StringBitCount(StackExchange.Redis.RedisKey key, long start, long end, StackExchange.Redis.CommandFlags flags) -> long
StackExchange.Redis.IDatabase.StringBitCount(StackExchange.Redis.RedisKey key, long start = 0, long end = -1, StackExchange.Redis.StringIndexType indexType = StackExchange.Redis.StringIndexType.Byte, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
-StackExchange.Redis.IDatabase.StringBitfield(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldCommandBuilder! builder, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?[]!
-StackExchange.Redis.IDatabase.StringBitfieldGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
-StackExchange.Redis.IDatabase.StringBitfieldIncrement(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?
-StackExchange.Redis.IDatabase.StringBitfieldSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.IDatabase.StringBitOperation(StackExchange.Redis.Bitwise operation, StackExchange.Redis.RedisKey destination, StackExchange.Redis.RedisKey first, StackExchange.Redis.RedisKey second = default(StackExchange.Redis.RedisKey), StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.IDatabase.StringBitOperation(StackExchange.Redis.Bitwise operation, StackExchange.Redis.RedisKey destination, StackExchange.Redis.RedisKey[]! keys, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.IDatabase.StringBitPosition(StackExchange.Redis.RedisKey key, bool bit, long start, long end, StackExchange.Redis.CommandFlags flags) -> long
@@ -966,10 +947,6 @@ StackExchange.Redis.IDatabaseAsync.StreamTrimAsync(StackExchange.Redis.RedisKey
StackExchange.Redis.IDatabaseAsync.StringAppendAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitCountAsync(StackExchange.Redis.RedisKey key, long start, long end, StackExchange.Redis.CommandFlags flags) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitCountAsync(StackExchange.Redis.RedisKey key, long start = 0, long end = -1, StackExchange.Redis.StringIndexType indexType = StackExchange.Redis.StringIndexType.Byte, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
-StackExchange.Redis.IDatabaseAsync.StringBitfieldAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldCommandBuilder! builder, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
-StackExchange.Redis.IDatabaseAsync.StringBitfieldGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
-StackExchange.Redis.IDatabaseAsync.StringBitfieldIncrementAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long increment, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
-StackExchange.Redis.IDatabaseAsync.StringBitfieldSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldEncoding encoding, StackExchange.Redis.BitfieldOffset offset, long value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitOperationAsync(StackExchange.Redis.Bitwise operation, StackExchange.Redis.RedisKey destination, StackExchange.Redis.RedisKey first, StackExchange.Redis.RedisKey second = default(StackExchange.Redis.RedisKey), StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitOperationAsync(StackExchange.Redis.Bitwise operation, StackExchange.Redis.RedisKey destination, StackExchange.Redis.RedisKey[]! keys, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IDatabaseAsync.StringBitPositionAsync(StackExchange.Redis.RedisKey key, bool bit, long start, long end, StackExchange.Redis.CommandFlags flags) -> System.Threading.Tasks.Task!
diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Unshipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Unshipped.txt
index eff457070..36fe35ed2 100644
--- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Unshipped.txt
+++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Unshipped.txt
@@ -1,9 +1,23 @@
abstract StackExchange.Redis.RedisResult.ToString(out string? type) -> string?
override sealed StackExchange.Redis.RedisResult.ToString() -> string!
override StackExchange.Redis.Role.Master.Replica.ToString() -> string!
+StackExchange.Redis.BitfieldOperation
+StackExchange.Redis.BitfieldOperation.BitfieldOperation() -> void
+StackExchange.Redis.BitFieldSubCommand
+StackExchange.Redis.BitFieldSubCommand.Get = 0 -> StackExchange.Redis.BitFieldSubCommand
+StackExchange.Redis.BitFieldSubCommand.Increment = 2 -> StackExchange.Redis.BitFieldSubCommand
+StackExchange.Redis.BitFieldSubCommand.Set = 1 -> StackExchange.Redis.BitFieldSubCommand
StackExchange.Redis.ClientInfo.Protocol.get -> StackExchange.Redis.RedisProtocol?
StackExchange.Redis.ConfigurationOptions.Protocol.get -> StackExchange.Redis.RedisProtocol?
StackExchange.Redis.ConfigurationOptions.Protocol.set -> void
+StackExchange.Redis.IDatabase.StringBitfield(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldOperation[]! subCommands, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?[]!
+StackExchange.Redis.IDatabase.StringBitfieldGet(StackExchange.Redis.RedisKey key, long offset, byte width, bool offsetByBit = true, bool unsigned = false, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
+StackExchange.Redis.IDatabase.StringBitfieldIncrement(StackExchange.Redis.RedisKey key, long offset, byte width, long increment, bool offsetByBit = true, bool unsigned = false, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?
+StackExchange.Redis.IDatabase.StringBitfieldSet(StackExchange.Redis.RedisKey key, long offset, byte width, long value, bool offsetByBit = true, bool unsigned = false, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
+StackExchange.Redis.IDatabaseAsync.StringBitfieldAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.BitfieldOperation[]! subCommands, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
+StackExchange.Redis.IDatabaseAsync.StringBitfieldGetAsync(StackExchange.Redis.RedisKey key, long offset, byte width, bool offsetByBit = true, bool unsigned = false, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
+StackExchange.Redis.IDatabaseAsync.StringBitfieldIncrementAsync(StackExchange.Redis.RedisKey key, long offset, byte width, long increment, bool offsetByBit = true, bool unsigned = false, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
+StackExchange.Redis.IDatabaseAsync.StringBitfieldSetAsync(StackExchange.Redis.RedisKey key, long offset, byte width, long value, bool offsetByBit = true, bool unsigned = false, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IServer.Protocol.get -> StackExchange.Redis.RedisProtocol
StackExchange.Redis.RedisFeatures.ClientId.get -> bool
StackExchange.Redis.RedisFeatures.Equals(StackExchange.Redis.RedisFeatures other) -> bool
@@ -25,6 +39,9 @@ StackExchange.Redis.ResultType.Null = 8 -> StackExchange.Redis.ResultType
StackExchange.Redis.ResultType.Push = 37 -> StackExchange.Redis.ResultType
StackExchange.Redis.ResultType.Set = 21 -> StackExchange.Redis.ResultType
StackExchange.Redis.ResultType.VerbatimString = 12 -> StackExchange.Redis.ResultType
+static StackExchange.Redis.BitfieldOperation.Get(long offset, byte width, bool offsetByBit = true, bool unsigned = false) -> StackExchange.Redis.BitfieldOperation
+static StackExchange.Redis.BitfieldOperation.Increment(long offset, byte width, long increment, bool offsetByBit = true, bool unsigned = false, StackExchange.Redis.BitfieldOverflowHandling overflowHandling = StackExchange.Redis.BitfieldOverflowHandling.Wrap) -> StackExchange.Redis.BitfieldOperation
+static StackExchange.Redis.BitfieldOperation.Set(long offset, byte width, long value, bool offsetByBit = true, bool unsigned = false) -> StackExchange.Redis.BitfieldOperation
static StackExchange.Redis.RedisResult.Create(StackExchange.Redis.RedisResult![]! values, StackExchange.Redis.ResultType resultType) -> StackExchange.Redis.RedisResult!
static StackExchange.Redis.RedisResult.Create(StackExchange.Redis.RedisValue[]! values, StackExchange.Redis.ResultType resultType) -> StackExchange.Redis.RedisResult!
virtual StackExchange.Redis.RedisResult.Length.get -> int
diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs
index 4a2f2a80f..6f4fbd4fd 100644
--- a/src/StackExchange.Redis/RedisDatabase.cs
+++ b/src/StackExchange.Redis/RedisDatabase.cs
@@ -2920,51 +2920,51 @@ public Task StringBitCountAsync(RedisKey key, long start = 0, long end = -
return ExecuteAsync(msg, ResultProcessor.Int64);
}
- public long?[] StringBitfield(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None)
+ public long?[] StringBitfield(RedisKey key, BitfieldOperation[] subCommands, CommandFlags flags = CommandFlags.None)
{
- var msg = builder.Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = subCommands.BuildMessage(Database, key, flags, this, out var server);
return ExecuteSync(msg, ResultProcessor.NullableInt64Array, defaultValue: Array.Empty(), server: server);
}
- public Task StringBitfieldAsync(RedisKey key, BitfieldCommandBuilder builder, CommandFlags flags = CommandFlags.None)
+ public Task StringBitfieldAsync(RedisKey key, BitfieldOperation[] subCommands, CommandFlags flags = CommandFlags.None)
{
- var msg = builder.Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = subCommands.BuildMessage(Database, key, flags, this, out var server);
return ExecuteAsync(msg, ResultProcessor.NullableInt64Array, defaultValue: Array.Empty(), server: server);
}
- public long StringBitfieldGet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None)
+ public long StringBitfieldGet(RedisKey key, long offset, byte width, bool offsetByBit = true, bool unsigned = false, CommandFlags flags = CommandFlags.None)
{
- var msg = new BitfieldCommandBuilder().Get(encoding, offset).Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = BitfieldOperation.Get(offset, width, offsetByBit, unsigned).BuildMessage(Database, key, flags, this, out var server);
return ExecuteSync(msg, ResultProcessor.Int64, server);
}
- public Task StringBitfieldGetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, CommandFlags flags = CommandFlags.None)
+ public Task StringBitfieldGetAsync(RedisKey key, long offset, byte width, bool offsetByBit = true, bool unsigned = false, CommandFlags flags = CommandFlags.None)
{
- var msg = new BitfieldCommandBuilder().Get(encoding, offset).Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = BitfieldOperation.Get(offset, width, offsetByBit, unsigned).BuildMessage(Database, key, flags, this, out var server);
return ExecuteAsync(msg, ResultProcessor.Int64, server);
}
- public long StringBitfieldSet(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None)
+ public long StringBitfieldSet(RedisKey key, long offset, byte width, long value, bool offsetByBit = true, bool unsigned = false, CommandFlags flags = CommandFlags.None)
{
- var msg = new BitfieldCommandBuilder().Set(encoding, offset, value).Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = BitfieldOperation.Set(offset, width, value, offsetByBit, unsigned).BuildMessage(Database, key, flags, this, out var server);
return ExecuteSync(msg, ResultProcessor.Int64, server);
}
- public Task StringBitfieldSetAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long value, CommandFlags flags = CommandFlags.None)
+ public Task StringBitfieldSetAsync(RedisKey key, long offset, byte width, long value, bool offsetByBit = true, bool unsigned = false, CommandFlags flags = CommandFlags.None)
{
- var msg = new BitfieldCommandBuilder().Set(encoding, offset, value).Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = BitfieldOperation.Set(offset, width, value, offsetByBit, unsigned).BuildMessage(Database, key, flags, this, out var server);
return ExecuteAsync(msg, ResultProcessor.Int64, server);
}
- public long? StringBitfieldIncrement(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None)
+ public long? StringBitfieldIncrement(RedisKey key, long offset, byte width, long increment, bool offsetByBit = true, bool unsigned = false, BitfieldOverflowHandling overflowHandling = Redis.BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None)
{
- var msg = new BitfieldCommandBuilder().Incrby(encoding, offset, increment, overflowHandling).Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = BitfieldOperation.Increment(offset,width, increment, offsetByBit, unsigned, overflowHandling).BuildMessage(Database, key, flags, this, out var server);
return ExecuteSync(msg, ResultProcessor.NullableInt64, server);
}
- public Task StringBitfieldIncrementAsync(RedisKey key, BitfieldEncoding encoding, BitfieldOffset offset, long increment, BitfieldOverflowHandling overflowHandling = BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None)
+ public Task StringBitfieldIncrementAsync(RedisKey key, long offset, byte width, long increment, bool offsetByBit = true, bool unsigned = false, BitfieldOverflowHandling overflowHandling = Redis.BitfieldOverflowHandling.Wrap, CommandFlags flags = CommandFlags.None)
{
- var msg = new BitfieldCommandBuilder().Incrby(encoding, offset, increment, overflowHandling).Build(Database, key, flags, this, out ServerEndPoint? server);
+ var msg = BitfieldOperation.Increment(offset,width, increment, offsetByBit, unsigned, overflowHandling).BuildMessage(Database, key, flags, this, out var server);
return ExecuteAsync(msg, ResultProcessor.NullableInt64, server);
}
diff --git a/tests/StackExchange.Redis.Tests/Bitfield.cs b/tests/StackExchange.Redis.Tests/Bitfield.cs
index 5cada2413..517c53bb7 100644
--- a/tests/StackExchange.Redis.Tests/Bitfield.cs
+++ b/tests/StackExchange.Redis.Tests/Bitfield.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using System;
+using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
@@ -17,23 +18,28 @@ public void TestBitfieldHappyPath()
RedisKey key = Me();
db.KeyDelete(key);
- var encoding = new BitfieldEncoding(isSigned: true, 10);
- var offset = new BitfieldOffset(true, 1);
+ var offset = 1;
+ byte width = 10;
+ var byBit = false;
+ var unsigned = false;
+
// should be the old value
- var setResult = db.StringBitfieldSet(key, encoding, offset, -255);
- var getResult = db.StringBitfieldGet(key, encoding, offset);
- var incrementResult = db.StringBitfieldIncrement(key, encoding, offset, -10);
+ var setResult = db.StringBitfieldSet(key, offset, width, -255, byBit, unsigned);
+ var getResult = db.StringBitfieldGet(key, offset, width, byBit, unsigned);
+ var incrementResult = db.StringBitfieldIncrement(key, offset, width, -10, byBit, unsigned);
Assert.Equal(0, setResult);
Assert.Equal(-255, getResult);
Assert.Equal(-265, incrementResult);
- encoding = new BitfieldEncoding(isSigned: false, 18);
- offset = new BitfieldOffset(false, 22);
+ width = 18;
+ unsigned = true;
+ offset = 22;
+ byBit = true;
- setResult = db.StringBitfieldSet(key, encoding, offset, 262123);
- getResult = db.StringBitfieldGet(key, encoding, offset);
- incrementResult = db.StringBitfieldIncrement(key, encoding, offset, 20);
+ setResult = db.StringBitfieldSet(key, offset, width, 262123, byBit, unsigned);
+ getResult = db.StringBitfieldGet(key, offset, width, byBit, unsigned);
+ incrementResult = db.StringBitfieldIncrement(key, offset, width, 20, byBit, unsigned);
Assert.Equal(0, setResult);
Assert.Equal(262123, getResult);
@@ -48,23 +54,27 @@ public async Task TestBitfieldHappyPathAsync()
RedisKey key = Me();
db.KeyDelete(key);
- var encoding = new BitfieldEncoding(isSigned: true, 10);
- var offset = new BitfieldOffset(true, 1);
+ var offset = 1;
+ byte width = 10;
+ var byBit = false;
+ var unsigned = false;
// should be the old value
- var setResult = await db.StringBitfieldSetAsync(key, encoding, offset, -255);
- var getResult = await db.StringBitfieldGetAsync(key, encoding, offset);
- var incrementResult = await db.StringBitfieldIncrementAsync(key, encoding, offset, -10);
+ var setResult = await db.StringBitfieldSetAsync(key, offset, width, -255, byBit, unsigned);
+ var getResult = await db.StringBitfieldGetAsync(key, offset, width, byBit, unsigned);
+ var incrementResult = await db.StringBitfieldIncrementAsync(key, offset, width, -10, byBit, unsigned);
Assert.Equal(0, setResult);
Assert.Equal(-255, getResult);
Assert.Equal(-265, incrementResult);
- encoding = new BitfieldEncoding(isSigned: false, 18);
- offset = new BitfieldOffset(false, 22);
+ width = 18;
+ unsigned = true;
+ offset = 22;
+ byBit = true;
- setResult = await db.StringBitfieldSetAsync(key, encoding, offset, 262123);
- getResult = await db.StringBitfieldGetAsync(key, encoding, offset);
- incrementResult = await db.StringBitfieldIncrementAsync(key, encoding, offset, 20);
+ setResult = await db.StringBitfieldSetAsync(key, offset, width, 262123, byBit, unsigned);
+ getResult = await db.StringBitfieldGetAsync(key, offset, width, byBit, unsigned);
+ incrementResult = await db.StringBitfieldIncrementAsync(key, offset, width, 20, byBit, unsigned);
Assert.Equal(0, setResult);
Assert.Equal(262123, getResult);
@@ -79,16 +89,17 @@ public async Task TestBitfieldMulti()
RedisKey key = Me();
db.KeyDelete(key);
- var builder = new BitfieldCommandBuilder()
- .Set(new BitfieldEncoding(isSigned: false, 3), new BitfieldOffset(false, 5), 7)
- .Get(new BitfieldEncoding(isSigned: false, 3), new BitfieldOffset(false, 5))
- .Incrby(new BitfieldEncoding(isSigned: false, 3), new BitfieldOffset(false, 5), -1)
- .Set(new BitfieldEncoding(isSigned: true, 45), new BitfieldOffset(true, 1), 17592186044415)
- .Get(new BitfieldEncoding(isSigned: true, 45), new BitfieldOffset(true, 1))
- .Incrby(new BitfieldEncoding(isSigned: true, 45), new BitfieldOffset(true, 1), 1,
- BitfieldOverflowHandling.Fail);
+ var subCommands = new[]
+ {
+ BitfieldOperation.Set(5, 3, 7, true, true),
+ BitfieldOperation.Get(5, 3, true, true),
+ BitfieldOperation.Increment(5, 3, -1, true, true),
+ BitfieldOperation.Set(1, 45, 17592186044415, false, false),
+ BitfieldOperation.Get(1, 45, false, false),
+ BitfieldOperation.Increment(1, 45, 1, false, false, BitfieldOverflowHandling.Fail)
+ };
- var res = await db.StringBitfieldAsync(key, builder);
+ var res = await db.StringBitfieldAsync(key, subCommands);
Assert.Equal(0, res[0]);
Assert.Equal(7, res[1]);
@@ -106,16 +117,32 @@ public async Task TestOverflows()
RedisKey key = Me();
db.KeyDelete(key);
- var encoding = new BitfieldEncoding(isSigned: true, 3);
- var offset = new BitfieldOffset(true, 3);
+ var offset = 3;
+ byte width = 3;
+ var byBit = false;
+ var unsigned = false;
- await db.StringBitfieldSetAsync(key, encoding, offset, 3);
- var incrFail = await db.StringBitfieldIncrementAsync(key, encoding, offset, 1, BitfieldOverflowHandling.Fail);
+ await db.StringBitfieldSetAsync(key, offset, width, 3, byBit, unsigned);
+ var incrFail = await db.StringBitfieldIncrementAsync(key, offset, width, 1, byBit, unsigned, BitfieldOverflowHandling.Fail);
Assert.Null(incrFail);
- var incrWrap = await db.StringBitfieldIncrementAsync(key, encoding, offset, 1);
+ var incrWrap = await db.StringBitfieldIncrementAsync(key, offset, width, 1, byBit, unsigned);
Assert.Equal(-4, incrWrap);
- await db.StringBitfieldSetAsync(key, encoding, offset, 3);
- var incrSat = await db.StringBitfieldIncrementAsync(key, encoding, offset, 1, BitfieldOverflowHandling.Saturate);
+ await db.StringBitfieldSetAsync(key, offset, width, 3, byBit, unsigned);
+ var incrSat = await db.StringBitfieldIncrementAsync(key, offset, width, 1, byBit, unsigned, BitfieldOverflowHandling.Saturate);
Assert.Equal(3, incrSat);
}
+
+ [Fact]
+ public void PreflightValidation()
+ {
+ using var conn = Create(require: RedisFeatures.v3_2_0);
+ var db = conn.GetDatabase();
+ RedisKey key = Me();
+ db.KeyDelete(key);
+
+ Assert.Throws(()=> db.StringBitfieldGet(key, 0, 0, false, false));
+ Assert.Throws(()=> db.StringBitfieldGet(key, 64, 0, false, true));
+ Assert.Throws(()=> db.StringBitfieldGet(key, 65, 0, false, false));
+ Assert.Throws(() => db.StringBitfield(key, new[] { new BitfieldOperation() { Offset = "0", SubCommand = BitFieldSubCommand.Set, Encoding = "i5" } }));
+ }
}
From a00aba5a0e6b0a5031c569514c05072eb3ed4a14 Mon Sep 17 00:00:00 2001
From: slorello89
Date: Fri, 1 Dec 2023 10:00:55 -0500
Subject: [PATCH 14/14] encoding -> string
---
src/StackExchange.Redis/APITypes/BitfieldOperation.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/StackExchange.Redis/APITypes/BitfieldOperation.cs b/src/StackExchange.Redis/APITypes/BitfieldOperation.cs
index 311502857..1802ceaa4 100644
--- a/src/StackExchange.Redis/APITypes/BitfieldOperation.cs
+++ b/src/StackExchange.Redis/APITypes/BitfieldOperation.cs
@@ -17,7 +17,7 @@ public struct BitfieldOperation
return $"{signedness}{size}";
}).ToArray();
- private static RedisValue CreateEncoding(bool unsigned, byte size)
+ private static string CreateEncoding(bool unsigned, byte size)
{
if (size == 0)
{
@@ -42,7 +42,7 @@ private static RedisValue CreateEncoding(bool unsigned, byte size)
internal string Offset;
internal long? Value;
internal BitFieldSubCommand SubCommand;
- internal RedisValue Encoding;
+ internal string Encoding;
internal BitfieldOverflowHandling? BitfieldOverflowHandling;
///