Protobuf different messages for the same field - protocol-buffers

is it possible to create a field that can hold different types of messages? Let's say I wanted to send a request to create a car, but it can have different types of windows in it, and each type requires different fields to be present:
message TintedWindows {
double tintPercent = 1;
string tintColor = 2;
}
message ArmoredWindows {
string armorClass = 1;
}
message CreateCarRequest {
string color = 1;
int wheels = 2;
int doors = 3;
Windows??? windows = 4;
}
Is there a way of doing that smoothly or I have to add all those messages and check which one is empty and which one is not:
message CreateCarRequest {
string color = 1;
int wheels = 2;
int doors = 3;
TintedWindows tinted = 4;
ArmoredWindows armored = 5;
}
then do: (pseudocode)
windowsInterface windows;
if req.tinted != null && req.armored == null {
windows = newTinted(req.tinted)
} else if req.tinted == null && req.armored != null {
windows = newArmored(req.armored)
} else {
throw error
}
I'm curently doing that using the second method and it's a bit cumbersome.

You can use Oneof.
message CreateCarRequest {
string color = 1;
uint32 wheels = 2;
uint32 doors = 3;
oneof windows {
TintedWindows tinted = 4;
ArmoredWindows armored = 5;
}
}
There is no int type (see scalar), you'll need to choose one of the available types, probably uint32 for number of wheels and doors.

Related

How to represent a mix of enum and oneof in protobuf

I am trying to create a protocol buffer message with fields that are either a message or one of a choice of some constant (like an enum). Something that is logically equivalent to:
message Error {
oneof error_type {
EMPTY_METHOD_NAME = 0
ExecutionError execution_error = 1;
}
message ExecutionError {
string value = 1;
}
}
Essentially, I would like a field that can represent either an error type that is just a name with no fields, or an error type that has fields. How would I do this with protobuf3?
See Enumerations in the Language Guide (proto3)
message Error {
oneof error_type {
Foo foo = 1;
ExecutionError execution_error = 2;
}
enum Foo {
X = 0;
Y = 1;
Z = 2;
}
message ExecutionError {
string value = 1;
}
}

How do I assign value to a repeated oneof field in a protobuf message?

I have a protobuf message CoverageReport like this:
message Deductible {
double amount = 1;
string currency = 2;
}
message Insurance{
string type = 1;
string policyNumber = 2;
string agreementName = 3;
string appliedTo = 4;
string validFrom = 5;
string validTo = 6;
Deductible deductible = 7;
}
message Warranty {
string type = 1;
string warrantyType = 2;
string agreementName = 3;
string appliedTo = 4;
string validFrom = 5;
string validTo = 6;
}
message Coverage {
oneof item {
Insurance insurance = 1;
Warranty warranty = 2;
}
}
message CoverageReport {
bool coverageAppliance = 1;
repeated Coverage coverages = 2;
}
In my program I'm trying to assign values to a message instance, but I'm not sure how to assign to the oneof field Coverage which should then be appended to Coverages, like this
I get a response from an api, which i unmarshal into the struct CoverageReport which has similar structure to the protobuf. Then i need to create a protobuf message using the values from the struct. But it doesn't seem to work to asssign to the one of field!
type CoverageReport struct {
CoverageAppliance string `json:"coverageAppliance"`
Coverages []struct {
Type string `json:"type"`
PolicyNumber string `json:"policyNumber,omitempty"`
AgreementName string `json:"agreementName"`
AppliedTo string `json:"appliedTo"`
ValidFrom string `json:"validFrom"`
ValidTo string `json:"validTo"`
Deductible struct {
Amount float64 `json:"amount"`
Currency string `json:"currency"`
} `json:"deductible,omitempty"`
WarrantyType string `json:"warrantyType,omitempty"`
} `json:"coverages"`
}
var coveragereport *CoverageReport
err = json.Unmarshal(body, &coveragereport)
var cr *vcsproto.CoverageReport
if coveragereport.CoverageAppliance == "Yes" {
cr.CoverageAppliance = true
}
for _, item := range coveragereport.Coverages {
if item.Type == "Warranty"{
var warranty *vcsproto.Warranty
warranty.Type = item.Type
warranty.WarrantyType = item.WarrantyType
warranty.AgreementName = item.AgreementName
warranty.AppliedTo = item.AppliedTo
warranty.ValidFrom = item.ValidFrom
warranty.ValidTo = item.ValidTo
var coverage *vcsproto.Coverage
coverage.Item.Warranty = warranty
cr.Coverages = append(cr.Coverages, coverage)
} else {
var insurance *vcsproto.Insurance
insurance.Type = item.Type
insurance.PolicyNumber = item.PolicyNumber
insurance.AgreementName = item.AgreementName
insurance.AppliedTo = item.AppliedTo
insurance.ValidFrom = item.ValidFrom
insurance.ValidTo = item.ValidTo.
insurance.Deductible.Currency = item.Deductible.Currency
insurance.Deductible.Amount = item.Deductible.Amount
var coverage *vcsproto.Coverage
coverage.Item.Insurance = Insurance
cr.Coverages = append(cr.Coverages, coverage)
}
}
Take a look in the generated code here.
You do not assign directly to the Warranty nor Insurance subfields, but directly to the Item field. so coverage.Item = {insurance/warranty} should work.
Also note that in your code you're assigning coverage.Item.Insurance = Insurance - you probably meant the second Insurance to be the variable insurance instead.

How to create all possible variations from single string presented in special format?

Let's say, I have following template.
Hello, {I'm|he is} a {notable|famous} person.
Result should be
Hello, I'm a notable person.
Hello, I'm a famous person.
Hello, he is a notable person.
Hello, he is a famous person.
The only possible solution I have in mind - full search, but it is not effective.
May be there is a good algorithm for such kind of job but I do not know what task about. All permutations in array is very close to this but I have no idea how to use it here.
Here is working solution (it's part of object, so here is only relevant part).
generateText() parses string and converts 'Hello, {1|2}, here {3,4}' into ['Hello', ['1', '2'], 'here', ['3', '4']]]
extractText() takes this multidimensional array and creates all possible strings
STATE_TEXT: 'TEXT',
STATE_INSIDE_BRACKETS: 'INSIDE_BRACKETS',
generateText: function(text) {
var result = [];
var state = this.STATE_TEXT;
var length = text.length;
var simpleText = '';
var options = [];
var singleOption = '';
var i = 0;
while (i < length) {
var symbol = text[i];
switch(symbol) {
case '{':
if (state === this.STATE_TEXT) {
simpleText = simpleText.trim();
if (simpleText.length) {
result.push(simpleText);
simpleText = '';
}
state = this.STATE_INSIDE_BRACKETS;
}
break;
case '}':
if (state === this.STATE_INSIDE_BRACKETS) {
singleOption = singleOption.trim();
if (singleOption.length) {
options.push(singleOption);
singleOption = '';
}
if (options.length) {
result.push(options);
options = [];
}
state = this.STATE_TEXT;
}
break;
case '|':
if (state === this.STATE_INSIDE_BRACKETS) {
singleOption = singleOption.trim();
if (singleOption.length) {
options.push(singleOption);
singleOption = '';
}
}
break;
default:
if (state === this.STATE_TEXT) {
simpleText += symbol;
} else if (state === this.STATE_INSIDE_BRACKETS) {
singleOption += symbol;
}
break;
}
i++;
}
return result;
},
extractStrings(generated) {
var lengths = {};
var currents = {};
var permutations = 0;
var length = generated.length;
for (var i = 0; i < length; i++) {
if ($.isArray(generated[i])) {
lengths[i] = generated[i].length;
currents[i] = lengths[i];
permutations += lengths[i];
}
}
var strings = [];
for (var i = 0; i < permutations; i++) {
var string = [];
for (var k = 0; k < length; k++) {
if (typeof lengths[k] === 'undefined') {
string.push(generated[k]);
continue;
}
currents[k] -= 1;
if (currents[k] < 0) {
currents[k] = lengths[k] - 1;
}
string.push(generated[k][currents[k]]);
}
strings.push(string.join(' '));
}
return strings;
},
The only possible solution I have in mind - full search, but it is not effective.
If you must provide full results, you must run full search. There is simply no way around it. You don't need all permutations, though: the number of results is equal to the product of the number of alternatives in each template.
Although there are multiple ways to implement this, recursion is among the most popular approaches. Here is some pseudo-code to get you started:
string[][] templates = {{"I'm", "he is"}, {"notable", "famous", "boring"}}
int[] pos = new int[templates.Length]
string[] fills = new string[templates.Length]
recurse(templates, fills, 0)
...
void recurse(string[][] templates, string[] fills, int pos) {
if (pos == fills.Length) {
formatResult(fills);
} else {
foreach option in templates[pos] {
fills[pos] = option
recurse(templates, fills, pos+1);
}
}
}
It seems like the best solution here is going to be n*m where n=the first array and m= the second array . There are nm required lines of output, which means that as long as you are only doing nm you aren't doing any extra work
The generic running time for this is where there is more than 2 arrays with options, it would be
n1*n2...*nm where each of those is equal to the size of the respective list
A nested loop where you just print out the value for the current index of the outer loop along with the current value for the index of the inner loop should do this properly

Printing Array with componentsJoinedByString: method

Hey guys im using the method above like:
string = [array componentsJoinedByString:#"\n"];
this prints out each obj in my array, but what it prints out is:
{
Selected = 0;
name = "boots";
number = 69;
}
{
Selected = 0;
name = house;
number = 1001;
}
}
Selected = 0;
name = shirt;
number = 1234;
}
{
Selected = 0;
name = Brewski;
number = 4567;
}
and i just want it to print out:
Brewski
Boots...
etc..
The objects in your array seem to be dictionaries. You should do this instead.
[[array valueForKey:#"name"] componentsJoinedByString:#"\n"]

Windows Phone 7 UserExtendedProperties

After being directed here:
http://msdn.microsoft.com/en-us/library/microsoft.phone.info.userextendedproperties.getvalue%28v=VS.92%29.aspx
I tried the following code on my sideloaded application. All that was written out was the 000001 value.
I knew that would be the case in the emulator, but I was hoping to get a real value when it was on my phone. Any ideas?
int ANIDLength = 32;
int ANIDOffset = 2;
string result = string.Empty;
object anid;
if (UserExtendedProperties.TryGetValue("ANID", out anid))
{
if (anid != null && anid.ToString().Length >= (ANIDLength + ANIDOffset))
{
result = anid.ToString().Substring(ANIDOffset, ANIDLength);
}
else
{
result = "000001";
}
}
You need to remove 1 from the calculation of your length check to account for the substring operation working on a zero based index:
if (anid != null && anid.ToString().Length >= (ANIDLength + ANIDOffset - 1))
This works on my machine:
private string GetAnid()
{
object anidValue;
int ANIDLength = 32;
int ANIDOffset = 2;
if (UserExtendedProperties.TryGetValue("ANID", out anidValue))
{
if (anidValue != null && anidValue.ToString().Length >= (ANIDLength + ANIDOffset - 1))
{
return anidValue.ToString().Substring(ANIDOffset, ANIDLength);
}
else
{
return "???";
}
}
else
{
return "???";
}
}

Resources