On 7/6/22 16:17, Ali Çehreli wrote:

> I would consider std.parallelism

And it looks more natural with a std.parallelism.Task:

struct Progress {
  size_t percent_;

  void set(size_t downloaded, size_t total) {
    if (total != 0) {
      import core.atomic: atomicStore;

      const value = cast(size_t)(float(downloaded) / float(total) * 100);
      atomicStore(percent_, value);
    }
  }

  size_t get() const {
    import core.atomic: atomicLoad;

    return atomicLoad(percent_);
  }
}

struct Request {
  string url;
  string result;
  Progress progress;
}

void download(Request * request) {
  import std.net.curl: HTTP;

  auto http = HTTP(request.url);

  http.onProgress((size_t dl, size_t dln, size_t ul, size_t uln) {
      if (dl != 0) {
        request.progress.set(dln, dl);
      }
      return 0;
    });

  http.onReceive((ubyte[] data) {
      request.result ~= (cast(char[])data);
      return data.length;
    });

  http.perform();
}

void main() {
  import std.parallelism : task;
  import std.stdio: writefln;

  auto request = Request("dlang.org");
  auto downloadTask = task!download(&request);
  downloadTask.executeInNewThread;

  foreach (i; 0 .. 10) {
    writefln!"Doing work on the side (%s)"(i);
    writefln!"Checking download progress: %s%%"(request.progress.get());

    import core.thread;
    Thread.sleep(100.msecs);
  }

  // Now we need the result before continuing:
  downloadTask.yieldForce();

writefln!"Downloaded %s bytes:\n%s"(request.result.length, request.result);
}

Ali

Reply via email to