Skip to content

Commit baa270b

Browse files
committed
Delta serializer work
1 parent c28e1a5 commit baa270b

File tree

3 files changed

+423
-255
lines changed

3 files changed

+423
-255
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
using Rewrite.Core;
2+
using Rewrite.RewriteCSharp;
3+
using Rewrite.RewriteCSharp.Tree;
4+
using Rewrite.RewriteJava.Tree;
5+
using static Rewrite.Rpc.RpcObjectData.ObjectState;
6+
7+
namespace Rewrite.Rpc;
8+
9+
public class DeltaSerializer
10+
{
11+
public List<RpcObjectData> Serialize(object? before, object? after)
12+
{
13+
return Serialize(before, after, after);
14+
}
15+
private List<RpcObjectData> Serialize(object? before, object? after, object? root)
16+
{
17+
var list = new List<RpcObjectData>();
18+
bool shouldWriteEndOfObject = ReferenceEquals(after, root);
19+
20+
if (after == null)
21+
{
22+
list.Add(new() { State = DELETE });
23+
if(shouldWriteEndOfObject)
24+
list.Add(new() { State = END_OF_OBJECT });
25+
return list;
26+
}
27+
28+
if (before == null)
29+
{
30+
// ADD case — send type and value
31+
list.Add(new()
32+
{
33+
State = ADD,
34+
ValueType = after.GetType().AssemblyQualifiedName,
35+
Value = after,
36+
});
37+
if(shouldWriteEndOfObject)
38+
list.Add(new() { State = END_OF_OBJECT });
39+
return list;
40+
}
41+
42+
if (!Equals(before, after))
43+
{
44+
list.Add(new()
45+
{
46+
State = CHANGE,
47+
ValueType = after.GetType().AssemblyQualifiedName,
48+
Value = after,
49+
});
50+
if(shouldWriteEndOfObject)
51+
list.Add(new() { State = END_OF_OBJECT });
52+
return list;
53+
}
54+
55+
// If no change:
56+
list.Add(new() { State = NO_CHANGE });
57+
if(shouldWriteEndOfObject)
58+
list.Add(new() { State = END_OF_OBJECT });
59+
return list;
60+
}
61+
62+
public T Deserialize<T>(object before, List<RpcObjectData> changes)
63+
{
64+
return (T)Deserialize(before, changes);
65+
}
66+
67+
public object Deserialize(object before, List<RpcObjectData> changes)
68+
{
69+
foreach (var change in changes)
70+
{
71+
switch (change.State)
72+
{
73+
case DELETE:
74+
return null!;
75+
case NO_CHANGE:
76+
return before;
77+
case ADD:
78+
case CHANGE:
79+
return change.Value!;
80+
case END_OF_OBJECT:
81+
continue;
82+
default:
83+
throw new InvalidOperationException($"Unsupported state: {change.State}");
84+
}
85+
}
86+
87+
return before;
88+
}
89+
90+
public abstract class DiffContext
91+
{
92+
public DeltaSerializer Serializer { get; }
93+
public List<RpcObjectData> Output { get; }
94+
95+
protected DiffContext(DeltaSerializer serializer, List<RpcObjectData> output)
96+
{
97+
Serializer = serializer;
98+
Output = output;
99+
}
100+
101+
public DiffContext<T> For<T>(T? after, T? before = default)
102+
{
103+
return new DiffContext<T>(before, after, Serializer, Output);
104+
}
105+
}
106+
public class DiffContext<T> : DiffContext
107+
{
108+
public T? Before { get; }
109+
public T? After { get; }
110+
111+
public DiffContext(T? before, T? after, DeltaSerializer serializer, List<RpcObjectData> output)
112+
: base(serializer, output)
113+
{
114+
Before = before;
115+
After = after;
116+
}
117+
118+
public void SerializeProperty<TProp>(
119+
Func<T, TProp?> selector,
120+
Action<TProp, DiffContext> visitIfChanged)
121+
{
122+
var beforeValue = Before != null ? selector(Before) : default;
123+
var afterValue = After != null ? selector(After) : default;
124+
125+
if (Equals(beforeValue, afterValue))
126+
{
127+
Output.Add(new() { State = NO_CHANGE });
128+
}
129+
else
130+
{
131+
Output.Add(new() { State = CHANGE });
132+
var childContext = new DiffContext<TProp>(beforeValue, afterValue, Serializer, Output);
133+
visitIfChanged(afterValue!, childContext);
134+
}
135+
}
136+
137+
public void SerializeLeaf<TProp>(Func<T, TProp?> selector)
138+
{
139+
var value = selector(After!);
140+
var beforeValue = Before != null ? selector(Before) : default;
141+
142+
if (Equals(value, beforeValue))
143+
{
144+
Output.Add(new() { State = NO_CHANGE });
145+
}
146+
else
147+
{
148+
Output.Add(new()
149+
{
150+
State = CHANGE,
151+
Value = value,
152+
ValueType = value?.GetType().AssemblyQualifiedName
153+
});
154+
}
155+
}
156+
}
157+
158+
}
159+
160+
public class CSharpDeltaSerializer : CSharpVisitor<DeltaSerializer.DiffContext>
161+
{
162+
public override J? VisitClassDeclaration(Cs.ClassDeclaration node, DeltaSerializer.DiffContext p)
163+
{
164+
var ctx = p.For(node);
165+
ctx.SerializeProperty(x => x.Name, (after, context) => VisitIdentifier(after, context));
166+
return node;
167+
}
168+
}

0 commit comments

Comments
 (0)