示例#1
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);
  }
}
示例#2
0
/*
 * layout_cipher() - Draws recover cipher
 *
 * INPUT
 *     - current_word: current word that is being typed in at this point in recovery
 *     - cipher: randomized cipher
 * OUTPUT
 *     none
 */
void layout_cipher(const char *current_word, const char *cipher)
{
    DrawableParams sp;
    const Font *title_font = get_body_font();
    Canvas *canvas = layout_get_canvas();

    call_leaving_handler();
    layout_clear();

    /* Draw prompt */
    sp.y = 11;
    sp.x = 4;
    sp.color = BODY_COLOR;
    draw_string(canvas, title_font, "Recovery Cipher:", &sp, 58, font_height(title_font) + 3);

    /* Draw current word */
    sp.y = 46;
    sp.x = 4;
    sp.color = BODY_COLOR;
    draw_string(canvas, title_font, current_word, &sp, 68, font_height(title_font));
    display_refresh();

    /* Animate cipher */
    layout_add_animation(&layout_animate_cipher, (void *)cipher,
                         CIPHER_ANIMATION_FREQUENCY_MS * 30);
}
示例#3
0
void layout_init(MessageLayout* layout,
                 void* storage) {

  upb_msg_field_iter it;
  for (upb_msg_field_begin(&it, layout->msgdef);
       !upb_msg_field_done(&it);
       upb_msg_field_next(&it)) {
    layout_clear(layout, storage, upb_msg_iter_field(&it));
  }
}
示例#4
0
/*
 * layout_pin() - Draws pin matrix
 *
 * INPUT
 *     - str: string prompt to display next to pin matrix
 *     - pin: randomized pin matric
 * OUTPUT
 *     none
 */
void layout_pin(const char *str, char pin[])
{
    DrawableParams sp;
    Canvas *canvas = layout_get_canvas();

    call_leaving_handler();
    layout_clear();

    /* Draw prompt */
    const Font *font = get_body_font();
    sp.y = 29;
    sp.x = (140 - calc_str_width(font, str)) / 2;
    sp.color = BODY_COLOR;
    draw_string(canvas, font, str, &sp, TITLE_WIDTH, font_height(font));
    display_refresh();

    /* Animate pin scrambling */
    layout_add_animation(&layout_animate_pin, (void *)pin, PIN_MAX_ANIMATION_MS);
}
示例#5
0
/*
 * layout_address_notification() - Display address notification
 *
 * INPUT
 *     - desc: description of address being shown (normal or multisig)
 *     - address: address to display both as string and QR
 *     - type: notification type
 * OUTPUT
 *      none
 */
void layout_address_notification(const char *desc, const char *address,
                                 NotificationType type)
{
    call_leaving_handler();
    layout_clear();

    Canvas *canvas = layout_get_canvas();
    DrawableParams sp;
    const Font *address_font = get_title_font();

    /* Unbold fonts if address becomes too long */
    if(calc_str_width(address_font, address) > TRANSACTION_WIDTH)
    {
        address_font = get_body_font();
    }

    /* Determine vertical alignment and body width */
    sp.y =  TOP_MARGIN_FOR_ONE_LINE;

    /* Draw address */
    sp.y += font_height(address_font) + ADDRESS_TOP_MARGIN;
    sp.x = LEFT_MARGIN;
    sp.color = BODY_COLOR;
    draw_string(canvas, address_font, address, &sp, TRANSACTION_WIDTH,
                font_height(address_font) + BODY_FONT_LINE_PADDING);

    /* Draw description */
    if(strcmp(desc, "") != 0)
    {
        sp.y = TOP_MARGIN_FOR_ONE_LINE;
        sp.x = MULTISIG_LEFT_MARGIN;
        sp.color = BODY_COLOR;
        draw_string(canvas, address_font, desc, &sp, TRANSACTION_WIDTH,
                    font_height(address_font) + BODY_FONT_LINE_PADDING);
    }

    layout_address(address);
    layout_notification_icon(type, &sp);
}
示例#6
0
/*
 * layout_transaction_notification() - Display transaction notification
 *
 * INPUT
 *     - amount: amount of transaction
 *     - address: destination address
 *     - type: notification type
 * OUTPUT
 *     none
 */
void layout_transaction_notification(const char *amount, const char *address,
                                     NotificationType type)
{
    call_leaving_handler();
    layout_clear();

    Canvas *canvas = layout_get_canvas();
    DrawableParams sp;
    const Font *amount_font = get_title_font();
    const Font *address_font = get_title_font();

    /* Unbold fonts if address becomes too long */
    if(calc_str_width(address_font, address) > TRANSACTION_WIDTH)
    {
        amount_font = get_body_font();
        address_font = get_body_font();
    }

    /* Determine vertical alignment and body width */
    sp.y =  TOP_MARGIN_FOR_ONE_LINE;

    /* Format amount line */
    char title[BODY_CHAR_MAX];
    snprintf(title, BODY_CHAR_MAX, "Send %s to", amount);

    /* Draw amount */
    sp.x = LEFT_MARGIN;
    sp.color = TITLE_COLOR;
    draw_string(canvas, amount_font, title, &sp, TRANSACTION_WIDTH, font_height(amount_font));

    /* Draw address */
    sp.y += font_height(address_font) + TRANSACTION_TOP_MARGIN;
    sp.x = LEFT_MARGIN;
    sp.color = BODY_COLOR;
    draw_string(canvas, address_font, address, &sp, TRANSACTION_WIDTH,
                font_height(address_font) + BODY_FONT_LINE_PADDING);

    layout_notification_icon(type, &sp);
}