efl_io_buffer: adopt read-only and read-write buffers.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Mon, 19 Dec 2016 18:49:29 +0000 (16:49 -0200)
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Mon, 19 Dec 2016 18:50:58 +0000 (16:50 -0200)
todo--, allow buffer backing store to be provided by Eina_Slice
(rdonly) or Eina_Rw_Slice (rdwr).

src/examples/ecore/efl_net_server_example.c
src/lib/efl/interfaces/efl_io_buffer.c
src/lib/efl/interfaces/efl_io_buffer.eo

index 22efdd0..3a9598e 100644 (file)
@@ -343,7 +343,7 @@ _server_client_add(void *data EINA_UNUSED, const Efl_Event *event)
          * One can change these to Efl_Io_File or event pipe to something
          * else like Efl_Io_Stdin, Efl_Io_Stdout and it would just work.
          */
-        Eina_Slice slice;
+        static const Eina_Slice hello_world_slice = EINA_SLICE_STR_LITERAL("Hello World!");
         Send_Recv_Data *d;
         Eo *send_buffer, *recv_buffer;
 
@@ -354,10 +354,8 @@ _server_client_add(void *data EINA_UNUSED, const Efl_Event *event)
              return;
           }
 
-        // TODO buffer constructor taking RO string
-        send_buffer = efl_add(EFL_IO_BUFFER_CLASS, NULL);
-        slice = (Eina_Slice)EINA_SLICE_STR("Hello World!");
-        efl_io_writer_write(send_buffer, &slice, NULL);
+        send_buffer = efl_add(EFL_IO_BUFFER_CLASS, NULL,
+                              efl_io_buffer_adopt_readonly(efl_added, hello_world_slice));
 
         /* Unlimited buffer to store the received data. */
         recv_buffer = efl_add(EFL_IO_BUFFER_CLASS, NULL);
index 66b5338..299fb56 100644 (file)
@@ -17,6 +17,7 @@ typedef struct _Efl_Io_Buffer_Data
    Eina_Bool closed;
    Eina_Bool can_read;
    Eina_Bool can_write;
+   Eina_Bool readonly;
 } Efl_Io_Buffer_Data;
 
 static Eina_Bool
@@ -25,6 +26,8 @@ _efl_io_buffer_realloc(Eo *o, Efl_Io_Buffer_Data *pd, size_t size)
    void *tmp;
    size_t limit = efl_io_buffer_limit_get(o);
 
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->readonly, EINA_FALSE);
+
    if ((limit > 0) && (size > limit))
      size = limit;
 
@@ -77,6 +80,7 @@ _efl_io_buffer_realloc_rounded(Eo *o, Efl_Io_Buffer_Data *pd, size_t size)
 EOLIAN static void
 _efl_io_buffer_preallocate(Eo *o, Efl_Io_Buffer_Data *pd, size_t size)
 {
+   EINA_SAFETY_ON_TRUE_RETURN(pd->readonly);
    EINA_SAFETY_ON_TRUE_RETURN(efl_io_closer_closed_get(o));
    if (pd->allocated < size)
      _efl_io_buffer_realloc_rounded(o, pd, size);
@@ -85,6 +89,7 @@ _efl_io_buffer_preallocate(Eo *o, Efl_Io_Buffer_Data *pd, size_t size)
 EOLIAN static void
 _efl_io_buffer_limit_set(Eo *o, Efl_Io_Buffer_Data *pd, size_t limit)
 {
+   EINA_SAFETY_ON_TRUE_RETURN(pd->readonly);
    EINA_SAFETY_ON_TRUE_RETURN(efl_io_closer_closed_get(o));
 
    if (pd->limit == limit) return;
@@ -125,6 +130,7 @@ EOLIAN static Eina_Binbuf *
 _efl_io_buffer_binbuf_steal(Eo *o, Efl_Io_Buffer_Data *pd)
 {
    Eina_Binbuf *ret;
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->readonly, NULL);
    EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(o), NULL);
 
    ret = eina_binbuf_manage_new(pd->bytes, efl_io_sizer_size_get(o), EINA_FALSE);
@@ -166,7 +172,7 @@ _efl_io_buffer_efl_object_destructor(Eo *o, Efl_Io_Buffer_Data *pd)
 
    if (pd->bytes)
      {
-        free(pd->bytes);
+        if (!pd->readonly) free(pd->bytes);
         pd->bytes = NULL;
         pd->allocated = 0;
         pd->used = 0;
@@ -244,6 +250,7 @@ _efl_io_buffer_efl_io_writer_write(Eo *o, Efl_Io_Buffer_Data *pd, Eina_Slice *sl
    size_t available, todo, write_pos, limit;
    int err = EINVAL;
 
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->readonly, EPERM);
    EINA_SAFETY_ON_NULL_RETURN_VAL(slice, EINVAL);
    EINA_SAFETY_ON_TRUE_GOTO(efl_io_closer_closed_get(o), error);
 
@@ -362,6 +369,13 @@ _efl_io_buffer_efl_io_sizer_resize(Eo *o, Efl_Io_Buffer_Data *pd, uint64_t size)
 
    if (efl_io_sizer_size_get(o) == size) return 0;
 
+   if (pd->readonly)
+     {
+        EINA_SAFETY_ON_TRUE_RETURN_VAL(size > pd->used, EPERM);
+        pd->used = size;
+        goto end;
+     }
+
    old_size = pd->used;
    pd->used = size;
 
@@ -378,6 +392,7 @@ _efl_io_buffer_efl_io_sizer_resize(Eo *o, Efl_Io_Buffer_Data *pd, uint64_t size)
    if (old_size < size)
      memset(pd->bytes + old_size, 0, size - old_size);
 
+ end:
    pos_read = efl_io_buffer_position_read_get(o);
    if (pos_read > size)
      efl_io_buffer_position_read_set(o, size);
@@ -500,6 +515,8 @@ _efl_io_buffer_position_write_set(Eo *o, Efl_Io_Buffer_Data *pd, uint64_t positi
    EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(o), EINA_FALSE);
 
    size = efl_io_sizer_size_get(o);
+   if (position < size)
+     EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->readonly, EINA_FALSE);
    EINA_SAFETY_ON_TRUE_RETURN_VAL(position > size, EINA_FALSE);
 
    if (pd->position_write == position) return EINA_TRUE;
@@ -524,4 +541,79 @@ _efl_io_buffer_position_write_get(Eo *o EINA_UNUSED, Efl_Io_Buffer_Data *pd)
    return pd->position_write;
 }
 
+EOLIAN static void
+_efl_io_buffer_adopt_readonly(Eo *o, Efl_Io_Buffer_Data *pd, const Eina_Slice slice)
+{
+   Eina_Bool changed_size;
+
+   EINA_SAFETY_ON_TRUE_RETURN(efl_io_closer_closed_get(o));
+
+   if (!pd->readonly) free(pd->bytes);
+   pd->readonly = EINA_TRUE;
+   pd->bytes = (uint8_t *)slice.bytes;
+   pd->allocated = slice.len;
+
+   changed_size = (pd->used != slice.len);
+   pd->used = slice.len;
+   efl_io_writer_can_write_set(o, EINA_FALSE);
+   if (pd->closed) return;
+
+   if (efl_io_buffer_position_read_get(o) > slice.len)
+     {
+        efl_io_buffer_position_read_set(o, slice.len);
+        if (pd->closed) return;
+     }
+
+   efl_io_buffer_position_write_set(o, slice.len);
+   if (pd->closed) return;
+
+   if (changed_size)
+     {
+        efl_event_callback_call(o, EFL_IO_SIZER_EVENT_SIZE_CHANGED, NULL);
+        if (pd->closed) return;
+     }
+
+   efl_event_callback_call(o, EFL_IO_BUFFER_EVENT_REALLOCATED, NULL);
+}
+
+EOLIAN static void
+_efl_io_buffer_adopt_readwrite(Eo *o, Efl_Io_Buffer_Data *pd, Eina_Rw_Slice slice)
+{
+   Eina_Bool changed_size;
+
+   EINA_SAFETY_ON_TRUE_RETURN(efl_io_closer_closed_get(o));
+
+   if (!pd->readonly) free(pd->bytes);
+   pd->readonly = EINA_FALSE;
+   pd->bytes = slice.bytes;
+   pd->allocated = slice.len;
+
+   changed_size = (pd->used != slice.len);
+   pd->used = slice.len;
+
+   efl_io_writer_can_write_set(o, (pd->limit == 0) ||
+                               (efl_io_buffer_position_write_get(o) < pd->limit));
+   if (pd->closed) return;
+
+   if (efl_io_buffer_position_read_get(o) > slice.len)
+     {
+        efl_io_buffer_position_read_set(o, slice.len);
+        if (pd->closed) return;
+     }
+
+   if (efl_io_buffer_position_write_get(o) > slice.len)
+     {
+        efl_io_buffer_position_write_set(o, slice.len);
+        if (pd->closed) return;
+     }
+
+   if (changed_size)
+     {
+        efl_event_callback_call(o, EFL_IO_SIZER_EVENT_SIZE_CHANGED, NULL);
+        if (pd->closed) return;
+     }
+
+   efl_event_callback_call(o, EFL_IO_BUFFER_EVENT_REALLOCATED, NULL);
+}
+
 #include "interfaces/efl_io_buffer.eo.c"
index 30b75d2..ee4d52c 100644 (file)
@@ -22,6 +22,39 @@ class Efl.Io.Buffer (Efl.Object, Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer, Ef
             }
         }
 
+        adopt_readonly {
+            [[Adopt a read-only slice as buffer's backing store.
+
+              The slice memory will not be copied and must remain
+              alive during buffer's lifetime. Usually this is
+              guaranteed by some global static-const memory or some
+              parent object and this buffer being a view of that -- be
+              aware of parent memory remaining alive, such as
+              "slice,changed" events.
+            ]]
+            params {
+                @in slice: const(Eina.Slice); [[Slice to adopt as read-only]]
+            }
+        }
+
+        adopt_readwrite {
+            [[Adopt a read-write slice as buffer's backing store.
+
+              The slice memory will not be copied and must remain
+              alive during buffer's lifetime. Usually this is
+              guaranteed by some global static memory or some
+              parent object and this buffer being a view of that -- be
+              aware of parent memory remaining alive, such as
+              "slice,changed" events.
+
+              The memory will be disposed using free() and reallocated
+              using realloc().
+            ]]
+            params {
+                @in slice: Eina.Rw_Slice; [[Slice to adopt as read-write]]
+            }
+        }
+
         @property limit {
             [[Limit how big the buffer can grow.
 
@@ -95,6 +128,9 @@ class Efl.Io.Buffer (Efl.Object, Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer, Ef
             [[Steals the internal buffer memory and returns it as a binbuf.
 
               The returned memory must be freed with eina_binbuf_free().
+
+              On failure, for example a read-only backing store was
+              adopted with @.adopt_readonly, NULL is returned.
             ]]
             return: free(own(ptr(Eina.Binbuf)), eina_binbuf_free) @warn_unused; [[Binbuf]]
         }