Skip to content

Commit a5b5663

Browse files
committed
fix list impls
1 parent b6afb31 commit a5b5663

File tree

7 files changed

+401
-85
lines changed

7 files changed

+401
-85
lines changed

eng/StackExchange.Redis.Build/RespCommandGenerator.cs

Lines changed: 148 additions & 81 deletions
Large diffs are not rendered by default.
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
using System.Runtime.CompilerServices;
2+
using RESPite.Messages;
3+
using StackExchange.Redis;
4+
5+
// ReSharper disable InconsistentNaming
6+
namespace RESPite.StackExchange.Redis;
7+
8+
internal static partial class RedisCommands
9+
{
10+
// this is just a "type pun" - it should be an invisible/magic pointer cast to the JIT
11+
public static ref readonly ListCommands Lists(this in RespContext context)
12+
=> ref Unsafe.As<RespContext, ListCommands>(ref Unsafe.AsRef(in context));
13+
}
14+
15+
public readonly struct ListCommands(in RespContext context)
16+
{
17+
public readonly RespContext Context = context; // important: this is the only field
18+
}
19+
20+
internal static partial class ListCommandsExtensions
21+
{
22+
/*
23+
[RespCommand]
24+
public static partial RespOperation<RedisValue> BLMove(
25+
this in ListCommands context,
26+
RedisKey source,
27+
RedisKey destination,
28+
ListSide sourceSide,
29+
ListSide destinationSide,
30+
double timeoutSeconds);
31+
32+
[RespCommand]
33+
public static partial RespOperation<RedisValue[]> BLMPop(
34+
this in ListCommands context,
35+
[RespKey] RedisKey[] keys,
36+
ListSide side,
37+
long count,
38+
double timeoutSeconds);
39+
40+
[RespCommand]
41+
public static partial RespOperation<RedisValue> BLPop(
42+
this in ListCommands context,
43+
[RespKey] RedisKey[] keys,
44+
double timeoutSeconds);
45+
46+
[RespCommand]
47+
public static partial RespOperation<RedisValue> BRPop(
48+
this in ListCommands context,
49+
[RespKey] RedisKey[] keys,
50+
double timeoutSeconds);
51+
52+
[RespCommand]
53+
public static partial RespOperation<RedisValue> BRPopLPush(
54+
this in ListCommands context,
55+
RedisKey source,
56+
RedisKey destination,
57+
double timeoutSeconds);
58+
*/
59+
60+
[RespCommand]
61+
public static partial RespOperation<RedisValue> LIndex(this in ListCommands context, RedisKey key, long index);
62+
63+
[RespCommand(Formatter = "LInsertFormatter.Instance")]
64+
public static partial RespOperation<long> LInsert(
65+
this in ListCommands context,
66+
RedisKey key,
67+
bool insertBefore,
68+
RedisValue pivot,
69+
RedisValue element);
70+
71+
private sealed class
72+
LInsertFormatter : IRespFormatter<(RedisKey Key, bool InsertBefore, RedisValue Pivot, RedisValue Element)>
73+
{
74+
public static readonly LInsertFormatter Instance = new();
75+
private LInsertFormatter() { }
76+
77+
public void Format(
78+
scoped ReadOnlySpan<byte> command,
79+
ref RespWriter writer,
80+
in (RedisKey Key, bool InsertBefore, RedisValue Pivot, RedisValue Element) request)
81+
{
82+
writer.WriteCommand(command, 4);
83+
writer.Write(request.Key);
84+
writer.WriteRaw(request.InsertBefore ? "$6\r\nBEFORE\r\n"u8 : "$5\r\nAFTER\r\n"u8);
85+
writer.Write(request.Pivot);
86+
writer.Write(request.Element);
87+
}
88+
}
89+
90+
[RespCommand]
91+
public static partial RespOperation<long> LLen(this in ListCommands context, RedisKey key);
92+
93+
[RespCommand]
94+
public static partial RespOperation<RedisValue> LMove(
95+
this in ListCommands context,
96+
RedisKey source,
97+
RedisKey destination,
98+
ListSide sourceSide,
99+
ListSide destinationSide);
100+
101+
[RespCommand]
102+
public static partial RespOperation<RedisValue> LPop(this in ListCommands context, RedisKey key);
103+
104+
[RespCommand]
105+
public static partial RespOperation<RedisValue[]> LPop(this in ListCommands context, RedisKey key, long count);
106+
107+
[RespCommand(Parser = "RespParsers.Int64Index")]
108+
public static partial RespOperation<long> LPos(
109+
this in ListCommands context,
110+
RedisKey key,
111+
RedisValue element,
112+
[RespPrefix("RANK"), RespIgnore(1)] long rank = 1,
113+
[RespPrefix("MAXLEN"), RespIgnore(0)] long maxLen = 0);
114+
115+
[RespCommand]
116+
public static partial RespOperation<long[]> LPos(
117+
this in ListCommands context,
118+
RedisKey key,
119+
RedisValue element,
120+
[RespPrefix("RANK"), RespIgnore(1)] long rank,
121+
[RespPrefix("MAXLEN"), RespIgnore(0)] long maxLen,
122+
[RespPrefix("COUNT")] long count);
123+
124+
[RespCommand]
125+
public static partial RespOperation<long> LPush(this in ListCommands context, RedisKey key, RedisValue element);
126+
127+
[RespCommand]
128+
public static partial RespOperation<long> LPush(this in ListCommands context, RedisKey key, RedisValue[] elements);
129+
130+
[RespCommand]
131+
public static partial RespOperation<long> LPushX(this in ListCommands context, RedisKey key, RedisValue element);
132+
133+
[RespCommand]
134+
public static partial RespOperation<long> LPushX(this in ListCommands context, RedisKey key, RedisValue[] elements);
135+
136+
[RespCommand]
137+
public static partial RespOperation<RedisValue[]> LRange(
138+
this in ListCommands context,
139+
RedisKey key,
140+
long start,
141+
long stop);
142+
143+
[RespCommand]
144+
public static partial RespOperation<long> LRem(
145+
this in ListCommands context,
146+
RedisKey key,
147+
long count,
148+
RedisValue element);
149+
150+
[RespCommand]
151+
public static partial RespOperation LSet(
152+
this in ListCommands context,
153+
RedisKey key,
154+
long index,
155+
RedisValue element);
156+
157+
[RespCommand]
158+
public static partial RespOperation LTrim(this in ListCommands context, RedisKey key, long start, long stop);
159+
160+
[RespCommand]
161+
public static partial RespOperation<RedisValue> RPop(this in ListCommands context, RedisKey key);
162+
163+
[RespCommand]
164+
public static partial RespOperation<RedisValue[]> RPop(this in ListCommands context, RedisKey key, long count);
165+
166+
[RespCommand]
167+
public static partial RespOperation<RedisValue> RPopLPush(this in ListCommands context, RedisKey source,
168+
RedisKey destination);
169+
170+
[RespCommand]
171+
public static partial RespOperation<long> RPush(this in ListCommands context, RedisKey key, RedisValue element);
172+
173+
[RespCommand]
174+
public static partial RespOperation<long> RPush(this in ListCommands context, RedisKey key, RedisValue[] elements);
175+
176+
[RespCommand]
177+
public static partial RespOperation<long> RPushX(this in ListCommands context, RedisKey key, RedisValue element);
178+
179+
[RespCommand]
180+
public static partial RespOperation<long> RPushX(this in ListCommands context, RedisKey key, RedisValue[] elements);
181+
182+
[RespCommand(Parser = "RespParsers.ListPopResult")]
183+
public static partial RespOperation<ListPopResult> LMPop(
184+
this in ListCommands context,
185+
[RespPrefix, RespKey] RedisKey[] keys,
186+
ListSide side,
187+
[RespIgnore(1), RespPrefix("COUNT")] long count = 1);
188+
}

src/RESPite.StackExchange.Redis/RespFormatters.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,23 @@ public static void Write(this ref RespWriter writer, in RedisKey key)
5757
}
5858
}
5959

60+
internal static void WriteBulkString(this ref RespWriter writer, ListSide side)
61+
{
62+
switch (side)
63+
{
64+
case ListSide.Left:
65+
writer.WriteRaw("$4\r\nLEFT\r\n"u8);
66+
break;
67+
case ListSide.Right:
68+
writer.WriteRaw("$5\r\nRIGHT\r\n"u8);
69+
break;
70+
default:
71+
Throw();
72+
break;
73+
}
74+
static void Throw() => throw new ArgumentOutOfRangeException(nameof(side));
75+
}
76+
6077
// ReSharper disable once MemberCanBePrivate.Global
6178
public static void Write(this ref RespWriter writer, in RedisValue value)
6279
{

src/RESPite.StackExchange.Redis/RespParsers.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public static class RespParsers
1515
public static IRespParser<DateTime?> DateTimeFromSeconds => TimeParser.FromSeconds;
1616
public static IRespParser<TimeSpan?> TimeSpanFromMilliseconds => TimeParser.FromMilliseconds;
1717
public static IRespParser<DateTime?> DateTimeFromMilliseconds => TimeParser.FromMilliseconds;
18+
internal static IRespParser<long> Int64Index => Int64DefaultNegativeOneParser.Instance;
19+
internal static IRespParser<ListPopResult> ListPopResult => DefaultParser.Instance;
1820

1921
public static RedisValue ReadRedisValue(ref RespReader reader)
2022
{
@@ -40,7 +42,7 @@ public static RedisKey ReadRedisKey(ref RespReader reader)
4042

4143
private sealed class DefaultParser : IRespParser<RedisValue>, IRespParser<RedisKey>,
4244
IRespParser<Lease<byte>>, IRespParser<RedisValue[]>, IRespParser<HashEntry[]>,
43-
IRespParser<RedisKey[]>
45+
IRespParser<RedisKey[]>, IRespParser<ListPopResult>
4446
{
4547
private DefaultParser() { }
4648
public static readonly DefaultParser Instance = new();
@@ -92,9 +94,27 @@ HashEntry[] IRespParser<HashEntry[]>.Parse(ref RespReader reader)
9294
return result;
9395
*/
9496
}
97+
98+
ListPopResult IRespParser<ListPopResult>.Parse(ref RespReader reader)
99+
{
100+
if (reader.IsNull) return global::StackExchange.Redis.ListPopResult.Null;
101+
reader.DemandAggregate();
102+
reader.MoveNext();
103+
var key = ReadRedisKey(ref reader);
104+
reader.MoveNext();
105+
var arr = reader.ReadArray(SharedReadRedisValue, scalar: true)!;
106+
return new(key, arr);
107+
}
95108
}
96109
}
97110

111+
internal sealed class Int64DefaultNegativeOneParser : IRespParser<long>, IRespInlineParser
112+
{
113+
private Int64DefaultNegativeOneParser() { }
114+
public static readonly Int64DefaultNegativeOneParser Instance = new();
115+
public long Parse(ref RespReader reader) => reader.IsNull ? -1 : reader.ReadInt64();
116+
}
117+
98118
internal sealed class TimeParser : IRespParser<TimeSpan?>, IRespParser<DateTime?>, IRespInlineParser
99119
{
100120
private readonly bool _millis;

src/RESPite/RespIgnoreAttribute.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.ComponentModel;
2+
using System.Diagnostics;
3+
4+
namespace RESPite;
5+
6+
[AttributeUsage(AttributeTargets.Parameter)]
7+
[Conditional("DEBUG"), ImmutableObject(true)]
8+
public sealed class RespIgnoreAttribute : Attribute
9+
{
10+
private readonly object _value;
11+
public object Value => _value;
12+
public RespIgnoreAttribute(string value) => _value = value;
13+
public RespIgnoreAttribute(long value) => _value = value;
14+
public RespIgnoreAttribute(bool value) => _value = value;
15+
}

src/RESPite/RespPrefixAttribute.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
namespace RESPite;
1+
using System.ComponentModel;
2+
using System.Diagnostics;
23

4+
namespace RESPite;
5+
6+
// note: omitting the token means that a collection-count prefix will be written
37
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true)]
4-
public sealed class RespPrefixAttribute(string token) : Attribute
8+
[Conditional("DEBUG"), ImmutableObject(true)]
9+
public sealed class RespPrefixAttribute(string token = "") : Attribute
510
{
611
public string Token => token;
712
}

src/RESPite/RespSuffixAttribute.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
namespace RESPite;
1+
using System.ComponentModel;
2+
using System.Diagnostics;
3+
4+
namespace RESPite;
25

36
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true)]
7+
[Conditional("DEBUG"), ImmutableObject(true)]
48
public sealed class RespSuffixAttribute(string token) : Attribute
59
{
610
public string Token => token;

0 commit comments

Comments
 (0)