sfml3-rb 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +9 -0
  3. data/CHANGELOG.md +43 -17
  4. data/README.md +97 -29
  5. data/ext/audio/audio_enums.c +58 -20
  6. data/ext/audio/listener.c +89 -6
  7. data/ext/audio/music.c +206 -5
  8. data/ext/audio/sound.c +175 -5
  9. data/ext/audio/sound_buffer.c +189 -47
  10. data/ext/audio/sound_buffer_recorder.c +83 -16
  11. data/ext/audio/sound_recorder.c +172 -52
  12. data/ext/audio/sound_source_cone.c +108 -29
  13. data/ext/audio/sound_stream.c +178 -5
  14. data/ext/core/exceptions.c +10 -8
  15. data/ext/core/unicode.c +12 -2
  16. data/ext/ext.c +4 -0
  17. data/ext/graphics/blend_mode.c +203 -53
  18. data/ext/graphics/circle.c +271 -4
  19. data/ext/graphics/color.c +240 -90
  20. data/ext/graphics/drawable.c +15 -4
  21. data/ext/graphics/font.c +138 -25
  22. data/ext/graphics/glyph.c +31 -8
  23. data/ext/graphics/image.c +180 -37
  24. data/ext/graphics/polygon.c +293 -26
  25. data/ext/graphics/rect.c +211 -54
  26. data/ext/graphics/rectangle.c +279 -26
  27. data/ext/graphics/render_state.c +116 -2
  28. data/ext/graphics/render_texture.c +163 -2
  29. data/ext/graphics/shader.c +283 -17
  30. data/ext/graphics/shape.c +252 -26
  31. data/ext/graphics/sprite.c +216 -25
  32. data/ext/graphics/stencil_mode.c +148 -39
  33. data/ext/graphics/target.c +67 -22
  34. data/ext/graphics/target.h +15 -15
  35. data/ext/graphics/text.c +306 -6
  36. data/ext/graphics/texture.c +257 -3
  37. data/ext/graphics/transform.c +178 -5
  38. data/ext/graphics/transformable.c +126 -2
  39. data/ext/graphics/vertex.c +79 -2
  40. data/ext/graphics/vertex_array.c +128 -16
  41. data/ext/graphics/vertex_buffer.c +124 -2
  42. data/ext/graphics/view.c +130 -2
  43. data/ext/network/ftp.c +249 -10
  44. data/ext/network/http.c +156 -38
  45. data/ext/network/ip_address.c +107 -26
  46. data/ext/network/network_enums.c +248 -141
  47. data/ext/network/packet.c +273 -39
  48. data/ext/network/socket_selector.c +91 -19
  49. data/ext/network/tcp_listener.c +75 -16
  50. data/ext/network/tcp_socket.c +128 -25
  51. data/ext/network/udp_socket.c +122 -26
  52. data/ext/ports.rb +7 -0
  53. data/ext/system/buffer.c +41 -12
  54. data/ext/system/clock.c +68 -9
  55. data/ext/system/input_stream.c +94 -42
  56. data/ext/system/sleep.c +10 -2
  57. data/ext/system/time.c +172 -34
  58. data/ext/system/vec2.c +156 -35
  59. data/ext/system/vec3.c +166 -35
  60. data/ext/window/clipboard.c +47 -17
  61. data/ext/window/context.c +59 -9
  62. data/ext/window/context_settings.c +116 -38
  63. data/ext/window/cursor.c +39 -9
  64. data/ext/window/event.c +163 -42
  65. data/ext/window/joystick.c +69 -3
  66. data/ext/window/keyboard.c +168 -116
  67. data/ext/window/mouse.c +36 -2
  68. data/ext/window/sensor.c +28 -2
  69. data/ext/window/touch.c +20 -2
  70. data/ext/window/video_mode.c +90 -19
  71. data/ext/window/vulkan.c +34 -6
  72. data/ext/window/window.c +340 -16
  73. data/lib/sfml/version.rb +1 -1
  74. data/sig/audio/audio_enums.rbs +30 -0
  75. data/sig/audio/listener.rbs +16 -0
  76. data/sig/audio/music.rbs +56 -0
  77. data/sig/audio/sound.rbs +51 -0
  78. data/sig/audio/sound_buffer.rbs +17 -0
  79. data/sig/audio/sound_buffer_recorder.rbs +14 -0
  80. data/sig/audio/sound_recorder.rbs +17 -0
  81. data/sig/audio/sound_source_cone.rbs +14 -0
  82. data/sig/audio/sound_stream.rbs +51 -0
  83. data/sig/graphics/blend_mode.rbs +29 -0
  84. data/sig/graphics/circle.rbs +44 -0
  85. data/sig/graphics/color.rbs +39 -0
  86. data/sig/graphics/drawable.rbs +5 -0
  87. data/sig/graphics/font.rbs +20 -0
  88. data/sig/graphics/glyph.rbs +7 -0
  89. data/sig/graphics/image.rbs +22 -0
  90. data/sig/graphics/polygon.rbs +42 -0
  91. data/sig/graphics/rect.rbs +33 -0
  92. data/sig/graphics/rectangle.rbs +42 -0
  93. data/sig/graphics/render_state.rbs +21 -0
  94. data/sig/graphics/render_texture.rbs +37 -0
  95. data/sig/graphics/shader.rbs +39 -0
  96. data/sig/graphics/shape.rbs +38 -0
  97. data/sig/graphics/sprite.rbs +34 -0
  98. data/sig/graphics/stencil_mode.rbs +18 -0
  99. data/sig/graphics/target.rbs +10 -0
  100. data/sig/graphics/text.rbs +48 -0
  101. data/sig/graphics/texture.rbs +34 -0
  102. data/sig/graphics/transform.rbs +37 -0
  103. data/sig/graphics/transformable.rbs +25 -0
  104. data/sig/graphics/vertex.rbs +17 -0
  105. data/sig/graphics/vertex_array.rbs +17 -0
  106. data/sig/graphics/vertex_buffer.rbs +22 -0
  107. data/sig/graphics/view.rbs +24 -0
  108. data/sig/network/ftp.rbs +46 -0
  109. data/sig/network/http.rbs +27 -0
  110. data/sig/network/ip_address.rbs +22 -0
  111. data/sig/network/network_enums.rbs +95 -0
  112. data/sig/network/packet.rbs +40 -0
  113. data/sig/network/socket_selector.rbs +14 -0
  114. data/sig/network/tcp_listener.rbs +13 -0
  115. data/sig/network/tcp_socket.rbs +18 -0
  116. data/sig/network/udp_socket.rbs +17 -0
  117. data/sig/system/buffer.rbs +11 -0
  118. data/sig/system/clock.rbs +13 -0
  119. data/sig/system/input_stream.rbs +7 -0
  120. data/sig/system/sleep.rbs +3 -0
  121. data/sig/system/time.rbs +28 -0
  122. data/sig/system/vec2.rbs +26 -0
  123. data/sig/system/vec3.rbs +27 -0
  124. data/sig/window/clipboard.rbs +8 -0
  125. data/sig/window/context.rbs +11 -0
  126. data/sig/window/context_settings.rbs +20 -0
  127. data/sig/window/cursor.rbs +6 -0
  128. data/sig/window/event.rbs +20 -0
  129. data/sig/window/joystick.rbs +15 -0
  130. data/sig/window/keyboard.rbs +10 -0
  131. data/sig/window/mouse.rbs +9 -0
  132. data/sig/window/sensor.rbs +8 -0
  133. data/sig/window/touch.rbs +6 -0
  134. data/sig/window/video_mode.rbs +16 -0
  135. data/sig/window/vulkan.rbs +7 -0
  136. data/sig/window/window.rbs +57 -0
  137. metadata +66 -2
data/ext/ports.rb CHANGED
@@ -34,10 +34,17 @@ module Ports
34
34
  'x86-linux-gnu' => { triple: 'i686-linux-gnu', multiarch: 'i386-linux-gnu',
35
35
  os: :linux, cpu: 'i686' },
36
36
  'aarch64-linux-gnu' => { triple: 'aarch64-linux-gnu', os: :linux, cpu: 'aarch64' },
37
+ 'arm-linux-gnu' => { triple: 'arm-linux-gnueabihf', os: :linux, cpu: 'arm' },
37
38
  'x86_64-linux-musl' => { triple: 'x86_64-unknown-linux-musl', os: :linux, cpu: 'x86_64' },
38
39
  'x86-linux-musl' => { triple: 'i686-unknown-linux-musl', os: :linux, cpu: 'i686' },
40
+ # These two deliberately omit the -unknown- Debian-musl entries above use:
41
+ # the triple must match musl-cross-make's TARGET exactly, since that string
42
+ # is both the compiler prefix and the sysroot path (see musl_sysroot).
43
+ 'aarch64-linux-musl' => { triple: 'aarch64-linux-musl', os: :linux, cpu: 'aarch64' },
44
+ 'arm-linux-musl' => { triple: 'arm-linux-musleabihf', os: :linux, cpu: 'arm' },
39
45
  'x64-mingw-ucrt' => { triple: 'x86_64-w64-mingw32', os: :windows, cpu: 'x86_64' },
40
46
  'x86-mingw32' => { triple: 'i686-w64-mingw32', os: :windows, cpu: 'i686' },
47
+ 'aarch64-mingw-ucrt' => { triple: 'aarch64-w64-mingw32', os: :windows, cpu: 'arm64' },
41
48
  'x86_64-darwin' => { triple: 'x86_64-apple-darwin', os: :darwin, cpu: 'x86_64' },
42
49
  'arm64-darwin' => { triple: 'aarch64-apple-darwin', os: :darwin, cpu: 'arm64' }
43
50
  }.freeze
data/ext/system/buffer.c CHANGED
@@ -7,23 +7,30 @@
7
7
 
8
8
  static VALUE rb_cBuffer;
9
9
 
10
- static void Buffer_free(void *ptr) {
10
+ static void Buffer_free(void* ptr) {
11
11
  sfBuffer_destroy(ptr);
12
12
  }
13
13
 
14
14
  static const rb_data_type_t Buffer_data_type = {
15
15
  .wrap_struct_name = "SFML::Buffer",
16
16
  .function = {.dmark = NULL, .dfree = Buffer_free, .dsize = NULL},
17
- .flags = RUBY_TYPED_FREE_IMMEDIATELY
18
- };
17
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY};
19
18
 
20
- static VALUE Buffer_wrap(VALUE klass, sfBuffer *buffer) {
19
+ static VALUE Buffer_wrap(VALUE klass, sfBuffer* buffer) {
21
20
  return TypedData_Wrap_Struct(klass, &Buffer_data_type, buffer);
22
21
  }
23
22
 
23
+ /* call-seq:
24
+ * Buffer.new -> Buffer
25
+ *
26
+ * Creates a new, empty byte buffer.
27
+ *
28
+ * @return [Buffer] a new, empty buffer
29
+ * @raise [NoMemoryError] if the underlying buffer could not be allocated
30
+ */
24
31
  static VALUE Buffer_new(VALUE klass) {
25
32
  VALUE self;
26
- sfBuffer *buffer = sfBuffer_create();
33
+ sfBuffer* buffer = sfBuffer_create();
27
34
 
28
35
  if (buffer == NULL) {
29
36
  rb_raise(rb_eNoMemError, "could not create buffer");
@@ -34,28 +41,50 @@ static VALUE Buffer_new(VALUE klass) {
34
41
  return self;
35
42
  }
36
43
 
44
+ /* call-seq: size -> Integer
45
+ *
46
+ * Returns the size of the buffer in bytes.
47
+ *
48
+ * @return [Integer] size in bytes
49
+ */
37
50
  static VALUE Buffer_get_size(VALUE self) {
38
51
  return SIZET2NUM(sfBuffer_getSize(Get_Buffer_Struct(self)));
39
52
  }
40
53
 
54
+ /* call-seq: data -> String
55
+ *
56
+ * Returns the raw bytes held by the buffer.
57
+ *
58
+ * @return [String] the raw bytes, as a binary String
59
+ */
41
60
  static VALUE Buffer_get_data(VALUE self) {
42
- sfBuffer *buffer = Get_Buffer_Struct(self);
61
+ sfBuffer* buffer = Get_Buffer_Struct(self);
43
62
  size_t size = sfBuffer_getSize(buffer);
44
- const uint8_t *data = sfBuffer_getData(buffer);
63
+ const uint8_t* data = sfBuffer_getData(buffer);
45
64
 
46
65
  if (data == NULL || size == 0) {
47
66
  return rb_str_new("", 0);
48
67
  }
49
68
 
50
- return rb_str_new((const char *) data, (long) size);
69
+ return rb_str_new((const char*)data, (long)size);
51
70
  }
52
71
 
72
+ /* call-seq: empty? -> true or false
73
+ *
74
+ * Returns +true+ if the buffer holds no bytes.
75
+ *
76
+ * @return [Boolean]
77
+ */
53
78
  static VALUE Buffer_is_empty(VALUE self) {
54
79
  return BOOL2RB(sfBuffer_getSize(Get_Buffer_Struct(self)) == 0);
55
80
  }
56
81
 
57
- void Init_Buffer(VALUE rb_module) {
58
- rb_cBuffer = rb_define_class_under(rb_module, "Buffer", rb_cObject);
82
+ /* Document-class: SFML::Buffer
83
+ * A raw byte buffer, as used for encoded/decoded audio and image data
84
+ * elsewhere in the library.
85
+ */
86
+ void Init_Buffer(VALUE rb_mSFML) {
87
+ rb_cBuffer = rb_define_class_under(rb_mSFML, "Buffer", rb_cObject);
59
88
 
60
89
  rb_define_singleton_method(rb_cBuffer, "new", Buffer_new, 0);
61
90
 
@@ -70,8 +99,8 @@ VALUE Get_Klass_Buffer(void) {
70
99
  return rb_cBuffer;
71
100
  }
72
101
 
73
- void *Get_Buffer_Struct(VALUE self) {
74
- sfBuffer *ptr;
102
+ void* Get_Buffer_Struct(VALUE self) {
103
+ sfBuffer* ptr;
75
104
  TypedData_Get_Struct(self, sfBuffer, &Buffer_data_type, ptr);
76
105
  return ptr;
77
106
  }
data/ext/system/clock.c CHANGED
@@ -9,23 +9,26 @@
9
9
 
10
10
  static VALUE rb_cClock;
11
11
 
12
- static sfClock *Clock_create() {
12
+ static sfClock* Clock_create() {
13
13
  return sfClock_create();
14
14
  }
15
15
 
16
- static void Clock_free(void *ptr) {
16
+ static void Clock_free(void* ptr) {
17
17
  sfClock_destroy(ptr);
18
18
  }
19
19
 
20
20
  static const rb_data_type_t Clock_data_type = {
21
21
  .wrap_struct_name = "SFML::Clock",
22
22
  .function = {.dmark = NULL, .dfree = Clock_free, .dsize = NULL},
23
- .flags = RUBY_TYPED_FREE_IMMEDIATELY
24
- };
23
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY};
25
24
 
26
- static VALUE Clock_new_from(VALUE klass, sfClock *clock) {
25
+ static VALUE Clock_new_from(VALUE klass, sfClock* clock) {
27
26
  VALUE self;
28
27
 
28
+ if (clock == NULL) {
29
+ rb_raise(rb_eNoMemError, "failed to allocate clock");
30
+ }
31
+
29
32
  self = TypedData_Wrap_Struct(klass, &Clock_data_type, clock);
30
33
 
31
34
  rb_obj_call_init(self, 0, NULL);
@@ -33,6 +36,13 @@ static VALUE Clock_new_from(VALUE klass, sfClock *clock) {
33
36
  return self;
34
37
  }
35
38
 
39
+ /* call-seq:
40
+ * Clock.new -> Clock
41
+ *
42
+ * Creates a new clock and starts it immediately.
43
+ *
44
+ * @return [Clock]
45
+ */
36
46
  static VALUE Clock_new(VALUE klass) {
37
47
  return Clock_new_from(klass, Clock_create());
38
48
  }
@@ -41,38 +51,87 @@ static VALUE Clock_init(VALUE self) {
41
51
  return self;
42
52
  }
43
53
 
54
+ /* call-seq: elapsed_time -> Time
55
+ *
56
+ * Returns the time elapsed on the clock.
57
+ *
58
+ * @return [Time] time elapsed since the clock was created, started, or last
59
+ * restarted/reset, whichever is most recent
60
+ */
44
61
  static VALUE Clock_get_elapsed_time(VALUE self) {
45
62
  return time_to_rb(sfClock_getElapsedTime(Get_Clock_Struct(self)));
46
63
  }
47
64
 
65
+ /* call-seq: restart! -> Time
66
+ *
67
+ * Restarts the clock (equivalent to #reset! followed by #start!) and
68
+ * returns the time elapsed before restarting.
69
+ *
70
+ * @return [Time]
71
+ */
48
72
  static VALUE Clock_restart(VALUE self) {
49
73
  return time_to_rb(sfClock_restart(Get_Clock_Struct(self)));
50
74
  }
51
75
 
76
+ /* call-seq: reset! -> Time
77
+ *
78
+ * Stops the clock and resets its elapsed time to zero, returning the time
79
+ * elapsed before resetting.
80
+ *
81
+ * @return [Time]
82
+ */
52
83
  static VALUE Clock_reset(VALUE self) {
53
84
  return time_to_rb(sfClock_reset(Get_Clock_Struct(self)));
54
85
  }
55
86
 
87
+ /* call-seq: running? -> true or false
88
+ *
89
+ * Returns +true+ while the clock is running, +false+ once it is stopped.
90
+ *
91
+ * @return [Boolean]
92
+ */
56
93
  static VALUE Clock_is_running(VALUE self) {
57
94
  return BOOL2RB(sfClock_isRunning(Get_Clock_Struct(self)));
58
95
  }
59
96
 
97
+ /* call-seq: start! -> self
98
+ *
99
+ * Resumes a stopped clock without resetting its elapsed time.
100
+ *
101
+ * @return [self]
102
+ */
60
103
  static VALUE Clock_start(VALUE self) {
61
104
  sfClock_start(Get_Clock_Struct(self));
62
105
  return self;
63
106
  }
64
107
 
108
+ /* call-seq: stop! -> self
109
+ *
110
+ * Pauses the clock; #elapsed_time keeps returning the time at which it
111
+ * was stopped until #start! or #restart! is called.
112
+ *
113
+ * @return [self]
114
+ */
65
115
  static VALUE Clock_stop(VALUE self) {
66
116
  sfClock_stop(Get_Clock_Struct(self));
67
117
  return self;
68
118
  }
69
119
 
120
+ /* call-seq: copy -> Clock
121
+ *
122
+ * Returns an independent copy of the clock.
123
+ *
124
+ * @return [Clock] an independent copy with the same elapsed/running state
125
+ */
70
126
  static VALUE Clock_copy(VALUE self) {
71
127
  return Clock_new_from(Get_Klass_Clock(), sfClock_copy(Get_Clock_Struct(self)));
72
128
  }
73
129
 
74
- void Init_Clock(VALUE rb_module) {
75
- rb_cClock = rb_define_class_under(rb_module, "Clock", rb_cObject);
130
+ /* Document-class: SFML::Clock
131
+ * A stopwatch for measuring elapsed time.
132
+ */
133
+ void Init_Clock(VALUE rb_mSFML) {
134
+ rb_cClock = rb_define_class_under(rb_mSFML, "Clock", rb_cObject);
76
135
 
77
136
  rb_define_singleton_method(rb_cClock, "new", Clock_new, 0);
78
137
 
@@ -89,8 +148,8 @@ void Init_Clock(VALUE rb_module) {
89
148
  rb_define_method(rb_cClock, "running?", Clock_is_running, 0);
90
149
  }
91
150
 
92
- void *Get_Clock_Struct(VALUE self) {
93
- sfClock *clock;
151
+ void* Get_Clock_Struct(VALUE self) {
152
+ sfClock* clock;
94
153
  TypedData_Get_Struct(self, sfClock, &Clock_data_type, clock);
95
154
  return clock;
96
155
  }
@@ -16,21 +16,20 @@ typedef struct {
16
16
 
17
17
  static VALUE rb_cInputStream;
18
18
 
19
- static void InputStream_mark(void *ptr) {
20
- InputStream *stream = ptr;
19
+ static void InputStream_mark(void* ptr) {
20
+ InputStream* stream = ptr;
21
21
 
22
22
  rb_gc_mark(stream->rb_io);
23
23
  }
24
24
 
25
- static void InputStream_free(void *ptr) {
25
+ static void InputStream_free(void* ptr) {
26
26
  free(ptr);
27
27
  }
28
28
 
29
29
  static const rb_data_type_t InputStream_data_type = {
30
30
  .wrap_struct_name = "SFML::InputStream",
31
31
  .function = {.dmark = InputStream_mark, .dfree = InputStream_free, .dsize = NULL},
32
- .flags = RUBY_TYPED_FREE_IMMEDIATELY
33
- };
32
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY};
34
33
 
35
34
  /* Callbacks run from C++ (SFML), so a Ruby exception must never unwind through
36
35
  those frames. Each body runs under rb_protect and reports failure as a
@@ -38,12 +37,12 @@ static const rb_data_type_t InputStream_data_type = {
38
37
  typedef struct {
39
38
  VALUE io;
40
39
  size_t size;
41
- void *data;
40
+ void* data;
42
41
  int64_t result;
43
42
  } ReadContext;
44
43
 
45
44
  static VALUE InputStream_read_body(VALUE v) {
46
- ReadContext *ctx = (ReadContext *) v;
45
+ ReadContext* ctx = (ReadContext*)v;
47
46
  VALUE str = rb_funcall(ctx->io, rb_intern("read"), 1, SIZET2NUM(ctx->size));
48
47
 
49
48
  if (NIL_P(str)) {
@@ -55,25 +54,31 @@ static VALUE InputStream_read_body(VALUE v) {
55
54
 
56
55
  long length = RSTRING_LEN(str);
57
56
 
58
- if ((size_t) length > ctx->size) {
59
- length = (long) ctx->size;
57
+ if ((size_t)length > ctx->size) {
58
+ length = (long)ctx->size;
60
59
  }
61
60
 
62
61
  if (length > 0) {
63
- memcpy(ctx->data, RSTRING_PTR(str), (size_t) length);
62
+ const unsigned char* src = (const unsigned char*)RSTRING_PTR(str);
63
+ unsigned char* dest = ctx->data;
64
+ long i;
65
+
66
+ for (i = 0; i < length; i++) {
67
+ dest[i] = src[i];
68
+ }
64
69
  }
65
70
 
66
- ctx->result = (int64_t) length;
71
+ ctx->result = (int64_t)length;
67
72
 
68
73
  return Qnil;
69
74
  }
70
75
 
71
- static int64_t InputStream_read(void *data, size_t size, void *userData) {
72
- InputStream *stream = userData;
76
+ static int64_t InputStream_read(void* data, size_t size, void* userData) {
77
+ InputStream* stream = userData;
73
78
  ReadContext ctx = {.io = stream->rb_io, .size = size, .data = data, .result = -1};
74
79
  int state = 0;
75
80
 
76
- rb_protect(InputStream_read_body, (VALUE) &ctx, &state);
81
+ rb_protect(InputStream_read_body, (VALUE)&ctx, &state);
77
82
 
78
83
  if (state) {
79
84
  rb_set_errinfo(Qnil);
@@ -90,20 +95,20 @@ typedef struct {
90
95
  } SeekContext;
91
96
 
92
97
  static VALUE InputStream_seek_body(VALUE v) {
93
- SeekContext *ctx = (SeekContext *) v;
98
+ SeekContext* ctx = (SeekContext*)v;
94
99
 
95
100
  rb_funcall(ctx->io, rb_intern("seek"), 2, SIZET2NUM(ctx->position), INT2NUM(SEEK_SET));
96
- ctx->result = (int64_t) ctx->position;
101
+ ctx->result = (int64_t)ctx->position;
97
102
 
98
103
  return Qnil;
99
104
  }
100
105
 
101
- static int64_t InputStream_seek(size_t position, void *userData) {
102
- InputStream *stream = userData;
106
+ static int64_t InputStream_seek(size_t position, void* userData) {
107
+ InputStream* stream = userData;
103
108
  SeekContext ctx = {.io = stream->rb_io, .position = position, .result = -1};
104
109
  int state = 0;
105
110
 
106
- rb_protect(InputStream_seek_body, (VALUE) &ctx, &state);
111
+ rb_protect(InputStream_seek_body, (VALUE)&ctx, &state);
107
112
 
108
113
  if (state) {
109
114
  rb_set_errinfo(Qnil);
@@ -113,55 +118,91 @@ static int64_t InputStream_seek(size_t position, void *userData) {
113
118
  return ctx.result;
114
119
  }
115
120
 
121
+ typedef struct {
122
+ VALUE io;
123
+ int64_t result;
124
+ } Int64Context;
125
+
126
+ /* NUM2LL is done here, inside the rb_protect-called body, rather than after
127
+ rb_protect returns: if the IO's #tell/#pos/#size/#length returns something
128
+ that doesn't convert cleanly to a C integer (a String, nil, a Bignum too
129
+ large for int64_t, a #to_int that itself raises), NUM2LL raises directly --
130
+ and unprotected, that exception would unwind straight through CSFML's (and
131
+ possibly SFML's C++) stack frames, exactly what rb_protect exists to
132
+ prevent here. */
116
133
  static VALUE InputStream_tell_body(VALUE v) {
117
- VALUE io = (VALUE) v;
134
+ Int64Context* ctx = (Int64Context*)v;
135
+ VALUE result;
118
136
 
119
- if (rb_respond_to(io, rb_intern("tell"))) {
120
- return rb_funcall(io, rb_intern("tell"), 0);
137
+ if (rb_respond_to(ctx->io, rb_intern("tell"))) {
138
+ result = rb_funcall(ctx->io, rb_intern("tell"), 0);
139
+ } else {
140
+ result = rb_funcall(ctx->io, rb_intern("pos"), 0);
121
141
  }
122
142
 
123
- return rb_funcall(io, rb_intern("pos"), 0);
143
+ ctx->result = NUM2LL(result);
144
+
145
+ return Qnil;
124
146
  }
125
147
 
126
- static int64_t InputStream_tell(void *userData) {
127
- InputStream *stream = userData;
148
+ static int64_t InputStream_tell(void* userData) {
149
+ InputStream* stream = userData;
150
+ Int64Context ctx = {.io = stream->rb_io, .result = -1};
128
151
  int state = 0;
129
- VALUE result = rb_protect(InputStream_tell_body, stream->rb_io, &state);
152
+
153
+ rb_protect(InputStream_tell_body, (VALUE)&ctx, &state);
130
154
 
131
155
  if (state) {
132
156
  rb_set_errinfo(Qnil);
133
157
  return -1;
134
158
  }
135
159
 
136
- return NUM2LL(result);
160
+ return ctx.result;
137
161
  }
138
162
 
139
163
  static VALUE InputStream_get_size_body(VALUE v) {
140
- VALUE io = (VALUE) v;
164
+ Int64Context* ctx = (Int64Context*)v;
165
+ VALUE result;
141
166
 
142
- if (rb_respond_to(io, rb_intern("size"))) {
143
- return rb_funcall(io, rb_intern("size"), 0);
167
+ if (rb_respond_to(ctx->io, rb_intern("size"))) {
168
+ result = rb_funcall(ctx->io, rb_intern("size"), 0);
169
+ } else {
170
+ result = rb_funcall(ctx->io, rb_intern("length"), 0);
144
171
  }
145
172
 
146
- return rb_funcall(io, rb_intern("length"), 0);
173
+ ctx->result = NUM2LL(result);
174
+
175
+ return Qnil;
147
176
  }
148
177
 
149
- static int64_t InputStream_get_size(void *userData) {
150
- InputStream *stream = userData;
178
+ static int64_t InputStream_get_size(void* userData) {
179
+ InputStream* stream = userData;
180
+ Int64Context ctx = {.io = stream->rb_io, .result = -1};
151
181
  int state = 0;
152
- VALUE result = rb_protect(InputStream_get_size_body, stream->rb_io, &state);
182
+
183
+ rb_protect(InputStream_get_size_body, (VALUE)&ctx, &state);
153
184
 
154
185
  if (state) {
155
186
  rb_set_errinfo(Qnil);
156
187
  return -1;
157
188
  }
158
189
 
159
- return NUM2LL(result);
190
+ return ctx.result;
160
191
  }
161
192
 
193
+ /* call-seq:
194
+ * InputStream.new(io) -> InputStream
195
+ *
196
+ * Wraps a Ruby object that responds to +#read+ (and ideally +#seek+/+#tell+
197
+ * or +#pos+, and +#size+ or +#length+) so it can be passed anywhere the
198
+ * library accepts a stream-based data source.
199
+ *
200
+ * @return [InputStream]
201
+ * @raise [ArgumentError] if +io+ does not respond to +#read+
202
+ */
162
203
  static VALUE InputStream_new(VALUE klass, VALUE rb_io) {
163
204
  VALUE self;
164
- InputStream *stream;
205
+ InputStream* stream;
165
206
 
166
207
  if (!rb_respond_to(rb_io, rb_intern("read"))) {
167
208
  rb_raise(rb_eArgError, "stream object must respond to #read");
@@ -181,12 +222,23 @@ static VALUE InputStream_new(VALUE klass, VALUE rb_io) {
181
222
  return self;
182
223
  }
183
224
 
225
+ /* call-seq: io -> Object
226
+ *
227
+ * Returns the IO-like object the stream was created from.
228
+ *
229
+ * @return [Object] the wrapped IO-like object
230
+ */
184
231
  static VALUE InputStream_get_io(VALUE self) {
185
- return ((InputStream *) Get_InputStream_Struct(self))->rb_io;
232
+ return ((InputStream*)Get_InputStream_Struct(self))->rb_io;
186
233
  }
187
234
 
188
- void Init_InputStream(VALUE rb_module) {
189
- rb_cInputStream = rb_define_class_under(rb_module, "InputStream", rb_cObject);
235
+ /* Document-class: SFML::InputStream
236
+ * Adapts any Ruby object that responds to +#read+ into the stream interface
237
+ * SFML's loaders expect, so resources can be loaded from something other
238
+ * than a filesystem path (e.g. an in-memory StringIO, or a custom source).
239
+ */
240
+ void Init_InputStream(VALUE rb_mSFML) {
241
+ rb_cInputStream = rb_define_class_under(rb_mSFML, "InputStream", rb_cObject);
190
242
 
191
243
  rb_define_singleton_method(rb_cInputStream, "new", InputStream_new, 1);
192
244
 
@@ -197,8 +249,8 @@ VALUE Get_Klass_InputStream(void) {
197
249
  return rb_cInputStream;
198
250
  }
199
251
 
200
- sfInputStream *Get_InputStream_Struct(VALUE self) {
201
- InputStream *ptr;
252
+ sfInputStream* Get_InputStream_Struct(VALUE self) {
253
+ InputStream* ptr;
202
254
  TypedData_Get_Struct(self, InputStream, &InputStream_data_type, ptr);
203
255
  return &ptr->stream;
204
256
  }
@@ -207,7 +259,7 @@ int InputStream_is_stream(VALUE rb_stream) {
207
259
  return rb_obj_is_kind_of(rb_stream, rb_cInputStream) ? 1 : 0;
208
260
  }
209
261
 
210
- sfInputStream *input_stream_from_rb(VALUE rb_stream, VALUE *holder) {
262
+ sfInputStream* input_stream_from_rb(VALUE rb_stream, VALUE* holder) {
211
263
  if (InputStream_is_stream(rb_stream)) {
212
264
  return Get_InputStream_Struct(rb_stream);
213
265
  }
data/ext/system/sleep.c CHANGED
@@ -5,12 +5,20 @@
5
5
  #include "system/time.h"
6
6
  #include "core/sfml.h"
7
7
 
8
+ /* call-seq:
9
+ * SFML.sleep(duration) -> duration
10
+ *
11
+ * Blocks the calling thread for +duration+, which may be a Time, a number
12
+ * of seconds, or anything #to_f-convertible.
13
+ *
14
+ * @return [Time, Numeric] +duration+
15
+ */
8
16
  static VALUE Sleep_sleep(VALUE module, VALUE rb_duration) {
9
17
  sfSleep(time_from_rb(rb_duration));
10
18
 
11
19
  return rb_duration;
12
20
  }
13
21
 
14
- void Init_Sleep(VALUE rb_module) {
15
- rb_define_module_function(rb_module, "sleep", Sleep_sleep, 1);
22
+ void Init_Sleep(VALUE rb_mSFML) {
23
+ rb_define_module_function(rb_mSFML, "sleep", Sleep_sleep, 1);
16
24
  }