#include "context_switcher/context_switcher.h"

#ifdef THREAD_SANITIZER
#include "context_switcher/tsan_fiber_api.h"
#endif

namespace context_switcher {

#ifdef CS_USE_CSCONTEXT
continuation switch_context(continuation &&cont) {
  continuation_t cont_pointer = cont.consume();
  continuation_t result = cscontext::__cs_switch_context(cont_pointer);
  return continuation{result};
}
#else
#ifdef THREAD_SANITIZER
continuation switch_context(continuation &&cont) {
  continuation_t cont_pointer = cont.consume();
  void *next_fiber = cont.get_tsan_fiber();
  void *old_fiber = __tsan_get_current_fiber();
  __tsan_switch_to_fiber(next_fiber, 0);
  fcontext::transfer_t transfer = fcontext::jump_fcontext(cont_pointer, old_fiber);
  if (transfer.data) {
    return continuation{transfer.continuation, transfer.data};
  } else {
    return continuation{nullptr, 0};
  }
}
#else
continuation switch_context(continuation &&cont) {
  continuation_t cont_pointer = cont.consume();
  fcontext::transfer_t transfer = fcontext::jump_fcontext(cont_pointer, (void *) 1);
  if (transfer.data) {
    return continuation{transfer.continuation};
  } else {
    return continuation{nullptr};
  }
}
#endif
#endif

}
