Beispiel #1
0
int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
  MessageHeader* self;
  char *name;
  const upb_fielddef* f;
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);

  if (TYPE(key) == T_STRING) {
    name = RSTRING_PTR(key);
  } else if (TYPE(key) == T_SYMBOL) {
    name = RSTRING_PTR(rb_id2str(SYM2ID(key)));
  } else {
    rb_raise(rb_eArgError,
             "Expected string or symbols as hash keys when initializing proto from hash.");
  }

  f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
  if (f == NULL) {
    rb_raise(rb_eArgError,
             "Unknown field name '%s' in initialization map entry.", name);
  }

  if (TYPE(val) == T_NIL) {
    return 0;
  }

  if (is_map_field(f)) {
    VALUE map;

    if (TYPE(val) != T_HASH) {
      rb_raise(rb_eArgError,
               "Expected Hash object as initializer value for map field '%s'.", name);
    }
    map = layout_get(self->descriptor->layout, Message_data(self), f);
    Map_merge_into_self(map, val);
  } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
    VALUE ary;

    if (TYPE(val) != T_ARRAY) {
      rb_raise(rb_eArgError,
               "Expected array as initializer value for repeated field '%s'.", name);
    }
    ary = layout_get(self->descriptor->layout, Message_data(self), f);
    for (int i = 0; i < RARRAY_LEN(val); i++) {
      VALUE entry = rb_ary_entry(val, i);
      if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
        entry = create_submsg_from_hash(f, entry);
      }

      RepeatedField_push(ary, entry);
    }
  } else {
    if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
      val = create_submsg_from_hash(f, val);
    }

    layout_set(self->descriptor->layout, Message_data(self), f, val);
  }
  return 0;
}
Beispiel #2
0
int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
  MessageHeader* self;
  VALUE method_str;
  char* name;
  const upb_fielddef* f;
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);

  if (!SYMBOL_P(key)) {
    rb_raise(rb_eArgError,
             "Expected symbols as hash keys in initialization map.");
  }

  method_str = rb_id2str(SYM2ID(key));
  name = RSTRING_PTR(method_str);
  f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
  if (f == NULL) {
    rb_raise(rb_eArgError,
             "Unknown field name '%s' in initialization map entry.", name);
  }

  if (is_map_field(f)) {
    VALUE map;

    if (TYPE(val) != T_HASH) {
      rb_raise(rb_eArgError,
               "Expected Hash object as initializer value for map field '%s'.", name);
    }
    map = layout_get(self->descriptor->layout, Message_data(self), f);
    Map_merge_into_self(map, val);
  } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
    VALUE ary;

    if (TYPE(val) != T_ARRAY) {
      rb_raise(rb_eArgError,
               "Expected array as initializer value for repeated field '%s'.", name);
    }
    ary = layout_get(self->descriptor->layout, Message_data(self), f);
    for (int i = 0; i < RARRAY_LEN(val); i++) {
      RepeatedField_push(ary, rb_ary_entry(val, i));
    }
  } else {
    layout_set(self->descriptor->layout, Message_data(self), f, val);
  }
  return 0;
}
Beispiel #3
0
/*
 * call-seq:
 *     FieldDescriptor.get(message) => value
 *
 * Returns the value set for this field on the given message. Raises an
 * exception if message is of the wrong type.
 */
VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
  DEFINE_SELF(FieldDescriptor, self, _self);
  MessageHeader* msg;
  TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
  if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
    rb_raise(rb_eTypeError, "get method called on wrong message type");
  }
  return layout_get(msg->descriptor->layout, Message_data(msg), self->fielddef);
}
Beispiel #4
0
/*
 * call-seq:
 *     Message.method_missing(*args)
 *
 * Provides accessors and setters for message fields according to their field
 * names. For any field whose name does not conflict with a built-in method, an
 * accessor is provided with the same name as the field, and a setter is
 * provided with the name of the field plus the '=' suffix. Thus, given a
 * message instance 'msg' with field 'foo', the following code is valid:
 *
 *     msg.foo = 42
 *     puts msg.foo
 *
 * This method also provides read-only accessors for oneofs. If a oneof exists
 * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to
 * the name of the field in that oneof that is currently set, or nil if none.
 */
VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
  MessageHeader* self;
  VALUE method_name, method_str;
  char* name;
  size_t name_len;
  bool setter;
  const upb_oneofdef* o;
  const upb_fielddef* f;

  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
  if (argc < 1) {
    rb_raise(rb_eArgError, "Expected method name as first argument.");
  }
  method_name = argv[0];
  if (!SYMBOL_P(method_name)) {
    rb_raise(rb_eArgError, "Expected symbol as method name.");
  }
  method_str = rb_id2str(SYM2ID(method_name));
  name = RSTRING_PTR(method_str);
  name_len = RSTRING_LEN(method_str);
  setter = false;

  // Setters have names that end in '='.
  if (name[name_len - 1] == '=') {
    setter = true;
    name_len--;
  }

  // Check for a oneof name first.
  o = upb_msgdef_ntoo(self->descriptor->msgdef,
                                          name, name_len);
  if (o != NULL) {
    if (setter) {
      rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
    }
    return which_oneof_field(self, o);
  }

  // Otherwise, check for a field with that name.
  f = upb_msgdef_ntof(self->descriptor->msgdef,
                                          name, name_len);

  if (f == NULL) {
    return rb_call_super(argc, argv);
  }

  if (setter) {
    if (argc < 2) {
      rb_raise(rb_eArgError, "No value provided to setter.");
    }
    layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
    return Qnil;
  } else {
    return layout_get(self->descriptor->layout, Message_data(self), f);
  }
}
Beispiel #5
0
/*
 * call-seq:
 *     Message.[](index) => value
 *
 * Accesses a field's value by field name. The provided field name should be a
 * string.
 */
VALUE Message_index(VALUE _self, VALUE field_name) {
  MessageHeader* self;
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
  Check_Type(field_name, T_STRING);
  const upb_fielddef* field =
      upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
  if (field == NULL) {
    return Qnil;
  }
  return layout_get(self->descriptor->layout, Message_data(self), field);
}
Beispiel #6
0
/*
 * call-seq:
 *     Message.method_missing(*args)
 *
 * Provides accessors and setters and methods to clear and check for presence of
 * message fields according to their field names.
 *
 * For any field whose name does not conflict with a built-in method, an
 * accessor is provided with the same name as the field, and a setter is
 * provided with the name of the field plus the '=' suffix. Thus, given a
 * message instance 'msg' with field 'foo', the following code is valid:
 *
 *     msg.foo = 42
 *     puts msg.foo
 *
 * This method also provides read-only accessors for oneofs. If a oneof exists
 * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to
 * the name of the field in that oneof that is currently set, or nil if none.
 *
 * It also provides methods of the form 'clear_fieldname' to clear the value
 * of the field 'fieldname'. For basic data types, this will set the default
 * value of the field.
 *
 * Additionally, it provides methods of the form 'has_fieldname?', which returns
 * true if the field 'fieldname' is set in the message object, else false. For
 * 'proto3' syntax, calling this for a basic type field will result in an error.
 */
VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
  MessageHeader* self;
  const upb_oneofdef* o;
  const upb_fielddef* f;

  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
  if (argc < 1) {
    rb_raise(rb_eArgError, "Expected method name as first argument.");
  }

  int accessor_type = extract_method_call(argv[0], self, &f, &o);
  if (accessor_type == METHOD_UNKNOWN || (o == NULL && f == NULL) ) {
    return rb_call_super(argc, argv);
  } else if (accessor_type == METHOD_SETTER) {
    if (argc != 2) {
      rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
    }
  } else if (argc != 1) {
    rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
  }

  // Return which of the oneof fields are set
  if (o != NULL) {
    if (accessor_type == METHOD_SETTER) {
      rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
    }

    const upb_fielddef* oneof_field = which_oneof_field(self, o);
    if (accessor_type == METHOD_PRESENCE) {
      return oneof_field == NULL ? Qfalse : Qtrue;
    } else if (accessor_type == METHOD_CLEAR) {
      if (oneof_field != NULL) {
	layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
      }
      return Qnil;
    } else {
      // METHOD_ACCESSOR
      return oneof_field == NULL ? Qnil :
	ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
    }
  // Otherwise we're operating on a single proto field
  } else if (accessor_type == METHOD_SETTER) {
    layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
    return Qnil;
  } else if (accessor_type == METHOD_CLEAR) {
    layout_clear(self->descriptor->layout, Message_data(self), f);
    return Qnil;
  } else if (accessor_type == METHOD_PRESENCE) {
    return layout_has(self->descriptor->layout, Message_data(self), f);
  } else {
    return layout_get(self->descriptor->layout, Message_data(self), f);
  }
}
Beispiel #7
0
VALUE layout_hash(MessageLayout* layout, void* storage) {
  upb_msg_field_iter it;
  st_index_t h = rb_hash_start(0);
  VALUE hash_sym = rb_intern("hash");
  for (upb_msg_field_begin(&it, layout->msgdef);
       !upb_msg_field_done(&it);
       upb_msg_field_next(&it)) {
    const upb_fielddef* field = upb_msg_iter_field(&it);
    VALUE field_val = layout_get(layout, storage, field);
    h = rb_hash_uint(h, NUM2LONG(rb_funcall(field_val, hash_sym, 0)));
  }
  h = rb_hash_end(h);

  return INT2FIX(h);
}
Beispiel #8
0
/*
 * call-seq:
 *     Message.to_h => {}
 *
 * Returns the message as a Ruby Hash object, with keys as symbols.
 */
VALUE Message_to_h(VALUE _self) {
  MessageHeader* self;
  VALUE hash;
  upb_msg_field_iter it;
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);

  hash = rb_hash_new();

  for (upb_msg_field_begin(&it, self->descriptor->msgdef);
       !upb_msg_field_done(&it);
       upb_msg_field_next(&it)) {
    const upb_fielddef* field = upb_msg_iter_field(&it);

    // For proto2, do not include fields which are not set.
    if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
	field_contains_hasbit(self->descriptor->layout, field) &&
	!layout_has(self->descriptor->layout, Message_data(self), field)) {
      continue;
    }

    VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self),
                                 field);
    VALUE msg_key   = ID2SYM(rb_intern(upb_fielddef_name(field)));
    if (is_map_field(field)) {
      msg_value = Map_to_h(msg_value);
    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
      msg_value = RepeatedField_to_ary(msg_value);
      if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
          RARRAY_LEN(msg_value) == 0) {
        continue;
      }

      if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
        for (int i = 0; i < RARRAY_LEN(msg_value); i++) {
          VALUE elem = rb_ary_entry(msg_value, i);
          rb_ary_store(msg_value, i, Message_to_h(elem));
        }
      }

    } else if (msg_value != Qnil &&
               upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
      msg_value = Message_to_h(msg_value);
    }
    rb_hash_aset(hash, msg_key, msg_value);
  }
  return hash;
}
Beispiel #9
0
void
layout_arrange(void) {
    Win *w;
    List *l, *ll;
    Layout *lo;
    Laydata *ld;
    unsigned int i, j, len;

    if(!(lo = layout_get(var.layout)))
        return;
    for(l = list_first(data.wins); l; l = l->next) {
        w = (Win*)l->ptr;
        if(!(w->tag & data.tag))
            XMoveWindow(data.dpy, w->win, w->x, (data.height * 2));
        else if(w->type & FULL)
            return;
        else if(w->type & FLOAT)
            XMoveWindow(data.dpy, w->win, w->x, w->y);
    }
    j = win_len(data.tag, NORMAL) - 1;
    if(win_first(data.tag, NORMAL, &l, &w))
        for(i = 0; w; win_next(data.tag, NORMAL, &l, &w), i++) {
            if(!(l = list_nth(lo->data, i)))
                l = list_last(lo->data);
            len = list_len(l);
            j = lo->tile ? MIN(len, j) : j;
            l = (List*)l->ptr;
            if(!(ll = list_nth(l, (j - i))))
                ll = list_last(l);
            ld = (Laydata*)ll->ptr;
            w->w = ((ld->width * data.width) / 100);
            w->h = ((ld->height * data.height) / 100);
            w->x = ((ld->x * data.width) / 100);
            w->x += var.gap_left + ROUND(var.gap_win / 2) - var.border_width;
            w->y = ((ld->y * data.height) / 100);
            w->y += var.gap_top + ROUND(var.gap_win / 2) - var.border_width;
            if(!lo->tile || i != len - 1) {
                w->w -= var.gap_win;
                w->h -= var.gap_win;
                win_resize(w);
            } else {
                tile(w, w->x, w->y, w->w, w->h, ld->col, ld->row);
                break;
            }
        }
}
Beispiel #10
0
char*
layout_add(char *name, char *str, int ntok) {
    List *l;
    Layout *lo;
    Laydata *ld;
    int i, j, a[6];
    char *t[ntok], *c[ntok];

    if(name) {
        free(var.layout);
        var.layout = estrdup(name);
        lo = emalloc(sizeof(Layout));
        lo->name = estrdup(name);
        lo->data = NULL;
        data.layouts = list_insert(data.layouts, lo, -1);
    } else if(str && var.layout) {
        c[0] = (t[0] = strtok(str, ";"));
        for(i = 1; (t[i] = strtok(NULL, ";")); i++) {
            for(; t[i] && !isdigit(t[i][0]) && t[i][0] != '-'; t[i]++);
            c[i] = t[i];
        }
        c[i] = NULL;
        for(i = 0, j = 0, l = NULL; c[i]; i++) {
            memset(&a, 0, sizeof(a));
            if((j = sscanf(c[i], "%d,%d,%d,%d,%d,%d", &a[0], &a[1], &a[2],
                           &a[3], &a[4], &a[5])) < 4)
                continue;
            ld = emalloc(sizeof(Laydata));
            ld->x = a[0];
            ld->y = a[1];
            ld->width = MAX(1, a[2]);
            ld->height = MAX(1, a[3]);
            ld->col = MAX(0, a[4]);
            ld->row = MAX(0, a[5]);
            l = list_insert(l, ld, -1);
        }
        if(!l)
            return "Nothing to insert into layout";
        if(!(lo = layout_get(var.layout)))
            return "Layout variable changed while parsing and do not exist.";
        lo->tile = j == 6;
        lo->data = list_insert(lo->data, l, -1);
    }
    return NULL;
}
Beispiel #11
0
void
layout_resize(int winc, int hinc) {
    Win *w;
    List *l, *ll;
    Layout *lo;
    Laydata *ld;
    int x, y, width, height;
    unsigned int i, j;

    if(!data.current || !(lo = layout_get(var.layout)))
        return;
    i = win_index(data.tag, NORMAL, data.current);
    j = win_len(data.tag, NORMAL) - 1;
    x = y = width = height = 0;
    if(win_first(data.tag, NORMAL, &l, &w))
        for(;w;) {
            if(!(l = list_nth(lo->data, i)))
                l = list_last(lo->data);
            j = lo->tile ? MIN(list_len(l), j) : j;
            l = (List*)l->ptr;
            if(!(ll = list_nth(l, (j - i))))
                ll = list_last(l);
            ld = (Laydata*)ll->ptr;
            if(!x && !y && !width && !height) {
                x = ld->x;
                y = ld->y;
                width = ld->width;
                height = ld->height;
                if(height >= 100)
                    hinc = 0;
                if(width >= 100)
                    winc = 0;
                i = 0;
                continue;
            }
            resize(x, width, &ld->x, (int*)&ld->width, winc);
            resize(y, height, &ld->y, (int*)&ld->height, hinc);
            win_next(data.tag, NORMAL, &l, &w);
            ++i;
        }
    layout_arrange();
}
Beispiel #12
0
VALUE Message_to_h(VALUE _self) {
  MessageHeader* self;
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);

  VALUE hash = rb_hash_new();

  upb_msg_field_iter it;
  for (upb_msg_field_begin(&it, self->descriptor->msgdef);
       !upb_msg_field_done(&it);
       upb_msg_field_next(&it)) {
    const upb_fielddef* field = upb_msg_iter_field(&it);
    VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self), field);
    VALUE msg_key   = ID2SYM(rb_intern(upb_fielddef_name(field)));
    if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
      msg_value = RepeatedField_to_ary(msg_value);
    }
    rb_hash_aset(hash, msg_key, msg_value);
  }
  return hash;
}
Beispiel #13
0
VALUE layout_inspect(MessageLayout* layout, void* storage) {
  VALUE str = rb_str_new2("");

  upb_msg_field_iter it;
  bool first = true;
  for (upb_msg_field_begin(&it, layout->msgdef);
       !upb_msg_field_done(&it);
       upb_msg_field_next(&it)) {
    const upb_fielddef* field = upb_msg_iter_field(&it);
    VALUE field_val = layout_get(layout, storage, field);

    if (!first) {
      str = rb_str_cat2(str, ", ");
    } else {
      first = false;
    }
    str = rb_str_cat2(str, upb_fielddef_name(field));
    str = rb_str_cat2(str, ": ");

    str = rb_str_append(str, rb_funcall(field_val, rb_intern("inspect"), 0));
  }

  return str;
}