-
-
Notifications
You must be signed in to change notification settings - Fork 221
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
Convert byte array to string #266
base: master
Are you sure you want to change the base?
Conversation
value.go
Outdated
@@ -53,6 +53,15 @@ func Null(iso *Isolate) *Value { | |||
return iso.null | |||
} | |||
|
|||
func NewStringFromByteArray(iso *Isolate, val []byte) (*Value, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will probably want the inverse to be supported as well (from the v8 value in JS back to Go)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in another comment, the reason behind implementing byte array to string is to overcome the challenges with null character in binary strings. I'm not sure for which scenario we would want to implement the reverse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When v8go converts a *Value
to a Go string
(e.g. with .String()
), it truncates the string at the first null character it encounters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a testcase in value_test.go where i am validating the same. If you print val.String(), it doesnt truncate the data even though there is a 0 byte in the input array.
Having said that, do you have any specific test-case? I can look into that scenario.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we could introduce a (v *Value) BinaryString() []byte
or (v *Value) BinaryString() BinaryString
depending on this outcome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When v8go converts a
*Value
to a Gostring
(e.g. with.String()
), it truncates the string at the first null character it encounters.
Note that we're not trying to solve #192 here. We may do that in a separate PR.
0cf95af
to
cd7a6a1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although the test could be improved and documentation could be added, the implementation looks good to me.
value_test.go
Outdated
inputString := "CN7ySxWjjWNpbYPB1n/TBR8avujZS2cHdXRR5ZM7Fi6QBjlVzBqPu0CI9pQXcW9fvbMXdqU+57XY/QdGozJT19+gbQDM0ZQVzjwqtpyLorcPHjMqum+7dHD6XF5cXo3NZlKGsxcnvSVyClBDU5M1dUCe8bB9yV0wVM6ge+0WAmTX2GYbncilTjDw0bSJI1Z+71NT8UQCfmimKhVxJiKrnkaTrTw2Ma/1I2w4Dny3cRlFtCtob9cvNOeeIm8HtQoi/7HXoE0uFr1C39OL2hCC1TJsxX94djtNFqd9aUOPYrwT+zErSokSvbNYS5WpEjEpRJze9+TCV9NLmqCnARK4Bw" | ||
byts, _ := base64.RawStdEncoding.DecodeString(inputString) | ||
|
||
expected := "ÞòK£cimÁÖÓ¾èÙKgutQå;.9UÌ»@öqo_½³v¥>çµØýF£2S×ß m" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems more complicated than it needs to be, which makes it hard to see the actual connection between the input and output if it fails and makes it harder to see what is actually being tested.
It seems like we just need the input to have the following for testing different edge cases:
- a null byte ('\x00') doesn't terminate the string
- bytes encoding a valid multi-byte UTF-8 encoding for a character should not be combined into a single character (e.g. []byte("ç") should have length 2 in the JS string)
- an invalid UTF-8 byte sequence (e.g. '\xff') gets preserved
inputString := "CN7ySxWjjWNpbYPB1n/TBR8avujZS2cHdXRR5ZM7Fi6QBjlVzBqPu0CI9pQXcW9fvbMXdqU+57XY/QdGozJT19+gbQDM0ZQVzjwqtpyLorcPHjMqum+7dHD6XF5cXo3NZlKGsxcnvSVyClBDU5M1dUCe8bB9yV0wVM6ge+0WAmTX2GYbncilTjDw0bSJI1Z+71NT8UQCfmimKhVxJiKrnkaTrTw2Ma/1I2w4Dny3cRlFtCtob9cvNOeeIm8HtQoi/7HXoE0uFr1C39OL2hCC1TJsxX94djtNFqd9aUOPYrwT+zErSokSvbNYS5WpEjEpRJze9+TCV9NLmqCnARK4Bw" | |
byts, _ := base64.RawStdEncoding.DecodeString(inputString) | |
expected := "�ÞòK�£�cim�ÁÖ�Ó���¾èÙKg�utQå�;�.��9UÌ��»@�ö��qo_½³�v¥>çµØý�F£2S×ß m" | |
expected := "a\x00ç\xffe" | |
input = []byte(expected) |
value_test.go
Outdated
if !val.IsString() { | ||
t.Errorf("expected string but got %s", reflect.TypeOf(val)) | ||
} | ||
if val.String() != expected { | ||
t.Errorf("expected not same as actual") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this also work for v8.NewValue(expected)
, in which case this isn't testing the distinguishing behaviour of this new method, which is that the bytes aren't interpreted as UTF-8 in the JS string. Since there isn't a v8go.String type, a workaround would be to test this in JS (e.g. getting the length and making sure it counts each byte in a UTF-8 encoded byte sequence)
value.go
Outdated
@@ -53,6 +53,15 @@ func Null(iso *Isolate) *Value { | |||
return iso.null | |||
} | |||
|
|||
func NewStringFromByteArray(iso *Isolate, val []byte) (*Value, error) { | |||
if iso == nil { | |||
return nil, errors.New("v8go: failed to create new Value: Isolate cannot be <nil>") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be treated as a bug, so should instead panic
to make sure the error is quickly noticed during testing..
0b5c75c
to
41fcfd3
Compare
Codecov Report
@@ Coverage Diff @@
## master #266 +/- ##
==========================================
- Coverage 95.86% 95.55% -0.31%
==========================================
Files 17 17
Lines 580 585 +5
==========================================
+ Hits 556 559 +3
- Misses 15 16 +1
- Partials 9 10 +1
Continue to review full report at Codecov.
|
v8go.h
Outdated
@@ -195,6 +195,7 @@ extern ValuePtr NewValueUndefined(IsolatePtr iso_ptr); | |||
extern ValuePtr NewValueInteger(IsolatePtr iso_ptr, int32_t v); | |||
extern ValuePtr NewValueIntegerFromUnsigned(IsolatePtr iso_ptr, uint32_t v); | |||
extern RtnValue NewValueString(IsolatePtr iso_ptr, const char* v, int v_length); | |||
extern RtnValue NewValueStringFromByteArray(IsolatePtr iso, const uint8_t* v, int len); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Value in the name doesn't seem necessary and doesn't match the function it is used from.
args := info.Args() | ||
input := args[0].String() | ||
if len(input) == 0 { | ||
//String() terminates input at null character. hence hardcoding for 3rd input |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A workaround is no longer needed for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.String() not working as expected. for input string a\x00\xffe
, it should return 4 bytes instead getting 5.
value.go
Outdated
@@ -53,6 +53,16 @@ func Null(iso *Isolate) *Value { | |||
return iso.null | |||
} | |||
|
|||
// NewStringFromByteArray returns V8::string from byte array. Converts each byte into equivalent character. | |||
func NewStringFromByteArray(iso *Isolate, val []byte) (*Value, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NewStringFromBytes would be a shorter name. Referring to the argument as a ByteArray doesn't make it any clearer and could even seem to refer to a JS array before looking at the parameter type.
The parameter name could be named bytes to be consistent with what it is referred to as in the function name.
Also, I've opened #277 since this should actually be returning a String type. We should add that type before adding a constructor for a string, so we don't need a breaking change to change it from Value to String later.
func NewStringFromByteArray(iso *Isolate, val []byte) (*Value, error) { | |
func NewStringFromBytes(iso *Isolate, bytes []byte) (*String, error) { |
@dylanahsmith @genevieve is this pull request something we can still move forward with? If not is there another known workaround for supporting the passing of a binary string from Go to JavaScript? Thanks. |
genevieve and I had been exploring using this library while working at Shopify, which didn't end up adopting this for production use and neither of us work at Shopify anymore. I think you will need help from someone else with merge access who has been more recently active on this project. |
Ok, sounds good. Thanks for the update and context @dylanahsmith. |
While using a base64 polyfill, encountered an issue where passing binary string from Go to JS didnt work as expected.
Code sample can be found here:
kuoruan/v8go-polyfills#4
Hence, added a new API that uses v8::String::NewFromOneByte to solve this scenario.