## InfAdoptedOperation InfAdoptedOperation — Operation that can be processed by InfAdoptedAlgorithm. |

## Stability Level

Unstable, unless otherwise indicated

## Synopsis

    #include <libinfinity/adopted/inf-adopted-operation.h>

                        InfAdoptedOperation;
    struct              InfAdoptedOperationIface;
    enum                InfAdoptedOperationFlags;
    enum                InfAdoptedConcurrencyId;
    gboolean            inf_adopted_operation_need_concurrency_id
                                                            (InfAdoptedOperation *operation,
                                                             InfAdoptedOperation *against);
    InfAdoptedConcurrencyId inf_adopted_operation_get_concurrency_id
                                                            (InfAdoptedOperation *operation,
                                                             InfAdoptedOperation *against);
    InfAdoptedOperation * inf_adopted_operation_transform   (InfAdoptedOperation *operation,
                                                             InfAdoptedOperation *against,
                                                             gint concurrency_id);
    InfAdoptedOperation * inf_adopted_operation_copy        (InfAdoptedOperation *operation);
    InfAdoptedOperationFlags inf_adopted_operation_get_flags
                                                            (InfAdoptedOperation *operation);
    void                inf_adopted_operation_apply         (InfAdoptedOperation *operation,
                                                             InfAdoptedUser *by,
                                                             InfBuffer *buffer);
    gboolean            inf_adopted_operation_is_reversible (InfAdoptedOperation *operation);
    InfAdoptedOperation * inf_adopted_operation_revert      (InfAdoptedOperation *operation);
    InfAdoptedOperation * inf_adopted_operation_make_reversible
                                                            (InfAdoptedOperation *operation,
                                                             InfAdoptedOperation *with,
                                                             InfBuffer *buffer);

## Object Hierarchy

      GInterface
       +----InfAdoptedOperation

      GFlags
       +----InfAdoptedOperationFlags

      GEnum
       +----InfAdoptedConcurrencyId

## Prerequisites

InfAdoptedOperation requires GObject.

## Known Implementations

InfAdoptedOperation is implemented by InfAdoptedNoOperation and InfAdoptedSplitOperation.

## Description

The InfAdoptedOperation interface must be implemented by operations that are supposed to be used by InfAdoptedAlgorithm. They basically need to define transformation rules for transformation against other operations.

## Details

### InfAdoptedOperation

    typedef struct _InfAdoptedOperation InfAdoptedOperation;

InfAdoptedOperation is an opaque data type. You should only access it via the public API functions.

### struct InfAdoptedOperationIface

    struct InfAdoptedOperationIface {
      gboolean (*need_concurrency_id)(InfAdoptedOperation* operation,
                                      InfAdoptedOperation* against);

      InfAdoptedConcurrencyId (*get_concurrency_id)(InfAdoptedOperation* op,
                                                    InfAdoptedOperation* against);

      InfAdoptedOperation* (*transform)(InfAdoptedOperation* operation,
                                        InfAdoptedOperation* against,
                                        InfAdoptedConcurrencyId concurrency_id);

      InfAdoptedOperation* (*copy)(InfAdoptedOperation* operation);

      InfAdoptedOperationFlags (*get_flags)(InfAdoptedOperation* operation);

      void (*apply)(InfAdoptedOperation* operation,
                    InfAdoptedUser* by,
                    InfBuffer* buffer);

      InfAdoptedOperation* (*revert)(InfAdoptedOperation* operation);

      InfAdoptedOperation* (*make_reversible)(InfAdoptedOperation* operation,
                                              InfAdoptedOperation* with,
                                              InfBuffer* buffer);
    };

The virtual methods that need to be implemented by an operation to be used with InfAdoptedAlgorithm.

`need_concurrency_id` () | Virtual function to determine whether a concurrency ID is required to transform `operation` against `against`.
`get_concurrency_id` () | Virtual function to obtain a concurrency ID for transforming `op` against `against`.
`transform` () | Virtual function that transform `operation` against `against` and returns a new InfAdoptedOperation as the result of the transformation. `concurrency_id` is either 1 or -1 and can be used to make a decision in case there is no other criteria to decide how to do the transformation, for example when both `operation` and `against` are inserting text at the same position in the buffer.
`copy` () | Virtual function that returns a copy of the operation.
`get_flags` () | Virtual function that returns the flags of the operation, see InfAdoptedOperationFlags.
`apply` () | Virtual function that applies the operation to the buffer. `by` is the user that applies the operation.
`revert` () | Virtual function that creates a new operation that undoes the effect of the operation. If `get_flags` does never return the `INF_ADOPTED_OPERATION_REVERSIBLE` flag set, then this is allowed to be `NULL`.
`make_reversible` () | Virtual function that creates a reversible operation out of the operation itself. If `get_flags` does always return the `INF_ADOPTED_OPERATION_REVERSIBLE` flag set, then this is allowed to be `NULL`. Some operations may not be reversible, but can be made reversible with some extra information such as another operation that collected information while being transformed, or the current buffer. This function should return either a new, reversible operation that has the same effect on a buffer, or `NULL` if the operation cannot be made reversible.

### enum InfAdoptedOperationFlags

    typedef enum {
      INF_ADOPTED_OPERATION_AFFECTS_BUFFER = 1 << 0,
      INF_ADOPTED_OPERATION_REVERSIBLE = 1 << 1
    } InfAdoptedOperationFlags;

Various flags for InfAdoptedOperation.

`INF_ADOPTED_OPERATION_AFFECTS_BUFFER` | The operation changes the content of the buffer.
`INF_ADOPTED_OPERATION_REVERSIBLE` | The operation is reversible, which means that `inf_adopted_operation_revert()` can be called to generate an operation that undoes the effect of the operation.

### enum InfAdoptedConcurrencyId

    typedef enum {
      INF_ADOPTED_CONCURRENCY_SELF = 1,
      INF_ADOPTED_CONCURRENCY_NONE = 0,
      INF_ADOPTED_CONCURRENCY_OTHER = -1
    } InfAdoptedConcurrencyId;

A concurrency ID is used to determine which operation to transform in case two similar operations are transformed against each other.

`INF_ADOPTED_CONCURRENCY_SELF` | Transform the operation itself.
`INF_ADOPTED_CONCURRENCY_NONE` | Unspecified which operation to transform.
`INF_ADOPTED_CONCURRENCY_OTHER` | Transform the other operation.

### inf_adopted_operation_need_concurrency_id ()

    gboolean            inf_adopted_operation_need_concurrency_id
                                                            (InfAdoptedOperation *operation,
                                                             InfAdoptedOperation *against);

This function returns whether transforming `operation` against `against` is not defined unambiguously. In that case, transformation requires a so-called concurrency ID which determines which of the two operations is transformed.

`operation` : | The InfAdoptedOperation to transform.
`against` : | The operation to transform against.
Returns : | Whether transformation of `operation` against `against` requires a concurrency ID to be defined.

### inf_adopted_operation_get_concurrency_id ()

    InfAdoptedConcurrencyId inf_adopted_operation_get_concurrency_id
                                                            (InfAdoptedOperation *operation,
                                                             InfAdoptedOperation *against);

This function returns a concurrency ID for transformation of `operation` against `against`. It always returns `INF_ADOPTED_CONCURRENCY_NONE` when `inf_adopted_operation_need_concurrency_id()` returns `TRUE` for `operation` and `against` (but that's not necessarily true the other way around), since it is not possible to decide which operation to transform without any additional information.

However, the function can be called on the same operations in a previous state. In some cases, a decision can be made based on those previous operations. This can then be used as concurrency ID to call `inf_adopted_operation_transform()`.

Note that the function is antisymmetric. If it returns `INF_ADOPTED_CONCURRENCY_SELF`, then it returns `INF_ADOPTED_CONCURRENCY_OTHER` for swapped arguments.

`operation` : | The InfAdoptedOperation to transform.
`against` : | The operation to transform against.
Returns : | A concurrency ID between `operation` and `against`. Can be `INF_ADOPTED_CONCURRENCY_NONE` in case no decision can be made.

### inf_adopted_operation_transform ()

    InfAdoptedOperation * inf_adopted_operation_transform   (InfAdoptedOperation *operation,
                                                             InfAdoptedOperation *against,
                                                             gint concurrency_id);

Performs an inclusion transformation of `operation` against `against`, meaning that the effect of `against` is included in `operation`.

If `inf_adopted_operation_need_concurrency_id()` returns `TRUE` for `operation` and `against`, then `concurrency_id` must not be `INF_ADOPTED_CONCURRENCY_NONE`. Otherwise, the parameter is ignored.

`operation` : | The InfAdoptedOperation to transform.
`against` : | The operation to transform against.
`concurrency_id` : | The concurrency ID for the transformation.
Returns : | The transformed InfAdoptedOperation, or `NULL` if the transformation failed.

### inf_adopted_operation_copy ()

    InfAdoptedOperation * inf_adopted_operation_copy        (InfAdoptedOperation *operation);

Returns a copy of `operation`.

`operation` : | The InfAdoptedOperation to copy.
Returns : | A copy of `operation`.

### inf_adopted_operation_get_flags ()

    InfAdoptedOperationFlags inf_adopted_operation_get_flags
                                                            (InfAdoptedOperation *operation);

Returns the flags for `operation`.

`operation` : | A InfAdoptedOperation.
Returns : | InfAdoptedOperationFlags for `operation`.

### inf_adopted_operation_apply ()

    void                inf_adopted_operation_apply         (InfAdoptedOperation *operation,
                                                             InfAdoptedUser *by,
                                                             InfBuffer *buffer);

Applies `operation` to `buffer`. The operation is considered to be applied by user `by`.

`operation` : | A InfAdoptedOperation.
`by` : | A InfAdoptedUser.
`buffer` : | The InfBuffer to apply the operation to.

### inf_adopted_operation_is_reversible ()

    gboolean            inf_adopted_operation_is_reversible (InfAdoptedOperation *operation);

Returns whether `operation` is reversible.

`operation` : | A InfAdoptedOperation.
Returns : | Whether `operation` is reversible.

### inf_adopted_operation_revert ()

    InfAdoptedOperation * inf_adopted_operation_revert      (InfAdoptedOperation *operation);

Returns a new InfAdoptedOperation that undoes the effect of `operation`. If `operation` and then its reverse operation are applied to a buffer (in that order), the buffer remains unchanged.

`operation` must be reversible for this function to be called (i.e. `inf_adopted_operation_is_reversible()` must return TRUE).

`operation` : | A InfAdoptedOperation.
Returns : | The reverse operation of `operation`.

### inf_adopted_operation_make_reversible ()

    InfAdoptedOperation * inf_adopted_operation_make_reversible
                                                            (InfAdoptedOperation *operation,
                                                             InfAdoptedOperation *with,
                                                             InfBuffer *buffer);

Some operations may not be reversible, but can be made reversible with some extra information such as another operation that collected enough information while being transformed, and the current buffer.

This function can only be called when `operation` is not yet reversible and returns a new operation that has the same effect as `operation`, but is reversible.

For example, an operation that deletes some range of text in a text editor is not reversible if it only stores the position and length of the range, but can be made reversible when it looks up what there is at that position in the buffer.

`operation` : | A InfAdoptedOperation.
`with` : | Another InfAdoptedOperation that emerged from `operation` by transforming it.
`buffer` : | A InfBuffer.
Returns : | A reversible InfAdoptedOperation, or `NULL` if `operation` cannot be made reversible with the given transformed operation `with` and `buffer`.

## See Also

InfAdoptedRequest, InfAdoptedAlgorithm