Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Added sink type toString to the serialization #2493

Merged
merged 1 commit into from Nov 23, 2020

Conversation

ferencdg
Copy link
Contributor

This change should reduce the number of memory allocations when using toString custom serialization

@@ -475,7 +475,10 @@ private template serializeValueImpl(Serializer, alias Policy) {
ser.serializeValue!(CustomType, ATTRIBUTES)(value.toRepresentation());
} else static if (isISOExtStringSerializable!TU) {
ser.serializeValue!(string, ATTRIBUTES)(value.toISOExtString());
} else static if (isStringSerializable!TU) {
} else static if (ObjectSupportSinkType!TU && SerializerSupportSinkType!(Serializer, TU)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ObjectSupportSinkType is not technically needed as SerializerSupportSinkType implicitly checks for the same

dg = (scope const(char)[] data)
{
static if (__traits(compiles, m_range ~= data))
m_range ~= data;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

in case the OutputRange supports more than just the put method(like with Appender) and operator~ is more optimized

Copy link
Contributor

Choose a reason for hiding this comment

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

It would be better to have this as a comment in the code ;)

Copy link
Contributor

@Geod24 Geod24 left a comment

Choose a reason for hiding this comment

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

The duplication between serializer and object handling looks a bit odd to me, but I'm not familiar enough with the code to suggest an alternative (or be 100% sure there's a better way either). So LGTM, minus a few comments. @s-ludwig ?

dg = (scope const(char)[] data)
{
static if (__traits(compiles, m_range ~= data))
m_range ~= data;
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be better to have this as a comment in the code ;)

import std.format : formattedWrite;
import vibe.data.json;

struct X (alias T)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
struct X (alias T)
struct X (bool hasSink)

Would be more descriptive, wouldn't it ?

Comment on lines 1929 to 1939
static if (isOutputRange!(R, char))
{
dg = (scope const(char)[] data)
{
static if (__traits(compiles, m_range ~= data))
m_range ~= data;
else
foreach (const c; data)
m_range.put(c);
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Having this delegate in the ctor has the downside of creating an extra GC allocation and an extra reference to m_range through the context.
It would be much better to move this delegate to the function that pass it (serializeSinkType) and use scope.
But even better, you could just make it a private method and pass &this.sink at L2028 instead of dg.

}

///
package template isObjectSupportSinkType (ObjectT)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
package template isObjectSupportSinkType (ObjectT)
package template isSinkSerializable (ObjectT)

I think the name is shorter and still fits with the existing style, what do you think ?

///
package template isObjectSupportSinkType (ObjectT)
{
enum isObjectSupportSinkType = is(typeof(ObjectT.toString(cast(SerializeSinkDg) null)) == void) &&
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
enum isObjectSupportSinkType = is(typeof(ObjectT.toString(cast(SerializeSinkDg) null)) == void) &&
enum isObjectSupportSinkType = is(typeof(ObjectT.toString(SerializeSinkDg.init))) &&

X.init is a neat way to get a default value typed as X. Remember, every cast is an aberration ;)
And I don't think we need to force the return type to be void. Why would we ?

private string s;
this (int i, string s) @safe {this.i = i; this.s = s;}

static if(T)
Copy link
Contributor

Choose a reason for hiding this comment

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

Space

{
private int i;
private string s;
this (int i, string s) @safe {this.i = i; this.s = s;}
Copy link
Contributor

Choose a reason for hiding this comment

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

If it's a struct, you don't need the ctor, do you ?
If you do, missing attributes.

}
}

public string toString () @safe
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
public string toString () @safe
public string toString () const @safe

///
package template isSerializerSupportSinkType (SerT, ObjT)
{
enum isSerializerSupportSinkType = is(typeof(SerT.serializeSinkType!(ObjT)(ObjT.init)) == void);
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment about void return as below

@ferencdg
Copy link
Contributor Author

The duplication between serializer and object handling looks a bit odd to me, but I'm not familiar enough with the code to suggest an alternative (or be 100% sure there's a better way either). So LGTM, minus a few comments. @s-ludwig ?

we have serializers like JsonSerializer(differenet from JsonStringSerializer) and JsonSerializer writes into a Json temporary object instead of an OutputRange. Because of this my thinking was that this sink serialization has to be supported by both the object and the serializer

@ferencdg
Copy link
Contributor Author

thans for the comments @Geod24, I fixed them(same for #2492)

This change should reduce the number of memory allocations when using toString custom serialization
{
static if (isOutputRange!(R, char))
{
static if (__traits(compiles, m_range ~= data))
Copy link
Member

Choose a reason for hiding this comment

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

This needs to perform jsonEscape, or is the idea is that the object is coupled with the output serialization format and can write arbitrary data?

@s-ludwig s-ludwig mentioned this pull request Nov 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants