Skip to content

Commit

Permalink
add: async support
Browse files Browse the repository at this point in the history
  • Loading branch information
tuna2134 committed Dec 19, 2022
1 parent 5a08443 commit 796e4e0
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion mizu/mizu.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ from typing import Optional

from .options import Options

import asyncio


class Mizu:
def __init__(self, options: Options = Options()) -> None:
def __init__(
self, options: Options = Options(), loop_ = asyncio.AbstractEventLoop
) -> None:
...

def parse(self, text: str) -> str:
Expand Down
15 changes: 15 additions & 0 deletions src/asyncio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use pyo3::prelude::*;

pub fn set_result(py: Python, loop_: PyObject, future: PyObject, result: String) -> PyResult<()> {
loop_.call_method1(
py,
"call_soon_threadsafe",
(future.getattr(py, "set_result")?, result),
)?;
Ok(())
}

pub fn create_future(py: Python, loop_: PyObject) -> PyResult<PyObject> {
let future = loop_.call_method0(py, "create_future")?;
Ok(future)
}
36 changes: 32 additions & 4 deletions src/core.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
use pyo3::prelude::*;

use crate::asyncio::*;
use pulldown_cmark::{html, Options, Parser};


/// Markdown parser.
///
/// Args:
/// options (Options): Options for parser.
#[pyclass]
#[pyo3(text_signature = "(options, /)")]
#[pyo3(text_signature = "(options, loop/)")]
pub struct Mizu {
options: Options,
loop_: Option<PyObject>,
}

#[pymethods]
impl Mizu {
#[new]
#[args(options = "Options::empty()")]
pub fn new(#[pyo3(from_py_with = "get_options")] options: Options) -> Self {
Mizu { options: options }
pub fn new(
#[pyo3(from_py_with = "get_options")] options: Options,
loop_: Option<PyObject>,
) -> Self {
Mizu {
options: options,
loop_: loop_,
}
}

/// Parse markdown text to html.
Expand All @@ -34,6 +41,27 @@ impl Mizu {
html::push_html(&mut output, parser);
Ok(output)
}

fn aioparse(&self, py: Python, text: String) -> PyResult<PyObject> {
if self.loop_.is_none() {
return Err(pyo3::exceptions::PyValueError::new_err(
"Event loop is not set",
));
}
let future = create_future(py, self.loop_.clone().unwrap())?;
let options = self.options.clone();
let fut_clone = future.clone_ref(py);
let loop_ = self.loop_.clone().unwrap();
std::thread::spawn(move || {
Python::with_gil(|py| {
let parser: Parser = Parser::new_ext(text.as_str(), options);
let mut output: String = String::new();
html::push_html(&mut output, parser);
set_result(py, loop_, fut_clone, output).unwrap();
});
});
Ok(future)
}
}

fn get_options(ob: &PyAny) -> PyResult<Options> {
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use pyo3::prelude::*;
mod asyncio;
mod core;

/// Mizu's core
Expand Down
10 changes: 10 additions & 0 deletions tests/test_async.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import pytest
from mizu import Mizu

import asyncio


@pytest.mark.asyncio
async def test_parse():
m = Mizu(loop_=asyncio.get_running_loop())
assert await m.aioparse("# hello") == "<h1>hello</h1>\n"

0 comments on commit 796e4e0

Please sign in to comment.