diff --git a/config/config.exs b/config/config.exs index 2cf1241..b59617f 100644 --- a/config/config.exs +++ b/config/config.exs @@ -28,3 +28,7 @@ use Mix.Config # here (which is why it is important to import them last). # # import_config "#{Mix.env()}.exs" + +config :id3, ID3.Native, + mode: :debug, + path: "native/id3" diff --git a/config/prod.exs b/config/prod.exs new file mode 100644 index 0000000..dc75212 --- /dev/null +++ b/config/prod.exs @@ -0,0 +1,5 @@ +use Mix.Config + +config :id3, ID3.Native, + mode: :release, + path: "native/id3" diff --git a/mix.exs b/mix.exs index 4dce65f..a7bf6b0 100644 --- a/mix.exs +++ b/mix.exs @@ -4,11 +4,10 @@ defmodule ID3.MixProject do def project do [ app: :id3, - version: "1.0.1", + version: "1.0.2", elixir: "~> 1.7", start_permanent: Mix.env() == :prod, - rustler_crates: rustler_crates(), - compilers: [:rustler] ++ Mix.compilers(), + compilers: Mix.compilers(), deps: deps(), # Docs @@ -39,16 +38,7 @@ defmodule ID3.MixProject do defp deps do [ {:ex_doc, "~> 0.19", only: :dev, runtime: false}, - {:rustler, "~> 0.21.0"} - ] - end - - defp rustler_crates do - [ - id3: [ - path: "native/id3", - mode: if(Mix.env() == :prod, do: :release, else: :debug) - ] + {:rustler, "~> 0.22.0"} ] end diff --git a/mix.lock b/mix.lock index c6a8408..9430a7b 100644 --- a/mix.lock +++ b/mix.lock @@ -1,9 +1,11 @@ %{ "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"}, - "ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0db1ee8d1547ab4877c5b5dffc6604ef9454e189928d5ba8967d4a58a801f161"}, - "makeup": {:hex, :makeup, "1.0.1", "82f332e461dc6c79dbd82fbe2a9c10d48ed07146f0a478286e590c83c52010b5", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "49736fe5b66a08d8575bf5321d716bac5da20c8e6b97714fec2bcd6febcfa1f8"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"}, - "nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"}, - "rustler": {:hex, :rustler, "0.21.0", "68cc4fc015d0b9541865ea78e78e9ef2dd91ee4be80bf543fd15791102a45aca", [:mix], [{:toml, "~> 0.5.2", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "e5429378c397f37f1091a35593b153aee1925e197c6842d04648d802edb52f80"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.15", "b29e8e729f4aa4a00436580dcc2c9c5c51890613457c193cc8525c388ccb2f06", [:mix], [], "hexpm", "044523d6438ea19c1b8ec877ec221b008661d3c27e3b848f4c879f500421ca5c"}, + "ex_doc": {:hex, :ex_doc, "0.25.1", "4b736fa38dc76488a937e5ef2944f5474f3eff921de771b25371345a8dc810bc", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "3200b0a69ddb2028365281fbef3753ea9e728683863d8cdaa96580925c891f67"}, + "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"}, + "rustler": {:hex, :rustler, "0.22.0", "e2930f9d6933e910f87526bb0a7f904e32b62a7e838a3ca4a884ee7fdfb957ed", [:mix], [{:toml, "~> 0.5.2", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "01f5989dd511ebec09be481e07d3c59773d5373c5061e09d3ebc3ef61811b49d"}, "toml": {:hex, :toml, "0.5.2", "e471388a8726d1ce51a6b32f864b8228a1eb8edc907a0edf2bb50eab9321b526", [:mix], [], "hexpm", "f1e3dabef71fb510d015fad18c0e05e7c57281001141504c6b69d94e99750a07"}, } diff --git a/native/id3/Cargo.toml b/native/id3/Cargo.toml index f78e81a..2fc9517 100644 --- a/native/id3/Cargo.toml +++ b/native/id3/Cargo.toml @@ -10,6 +10,6 @@ path = "src/lib.rs" crate-type = ["dylib"] [dependencies] -rustler = "0.21" +rustler = "0.22" lazy_static = "1.4" id3 = "0.5" diff --git a/native/id3/src/lib.rs b/native/id3/src/lib.rs index ef52a2f..35eba86 100644 --- a/native/id3/src/lib.rs +++ b/native/id3/src/lib.rs @@ -5,44 +5,35 @@ mod nif_converter; use crate::nif_converter::{ID3Picture, NaiveDateTime, NifBinary}; use id3::{Tag, Version}; -use rustler::{rustler_export_nifs, Encoder, Env, NifResult, NifStruct, Term}; +use rustler::{init, Encoder, Env, NifStruct, Term}; mod atoms { - use rustler::rustler_atoms; - - rustler_atoms! { - atom ok; - atom error; - //atom __true__ = "true"; - //atom __false__ = "false"; - atom file_open_error; - atom tag_write_error; + use rustler::atoms; + + atoms! { + ok, + error, + file_open_error, + tag_write_error, } } -rustler_export_nifs! { - "Elixir.ID3.Native", - [ - ("get_major_frames", 1, major_frames), - ("write_major_frames", 2, write_major_frames), - ], - None -} +init!("Elixir.ID3.Native", [major_frames, write_major_frames]); #[derive(NifStruct)] #[module = "ID3.Tag"] /// Struct for passing major tag data to/from Elixir. -struct MajorFrames<'a> { +struct MajorFrames { // pub comments: Option, pub year: Option, pub date_recorded: Option, pub date_released: Option, - pub artist: Option<&'a str>, - pub album_artist: Option<&'a str>, - pub album: Option<&'a str>, - pub title: Option<&'a str>, + pub artist: Option, + pub album_artist: Option, + pub album: Option, + pub title: Option, pub duration: Option, - pub genre: Option<&'a str>, + pub genre: Option, pub disc: Option, pub total_discs: Option, pub track: Option, @@ -50,9 +41,56 @@ struct MajorFrames<'a> { pub pictures: Vec, } -fn major_frames<'a>(env: Env<'a>, args: &[Term<'a>]) -> NifResult> { - let path: String = (args[0].decode())?; +enum ReadResult { + Ok(MajorFrames), + Error(), +} + +impl ReadResult { + fn ok(frames: MajorFrames) -> ReadResult { + ReadResult::Ok(frames) + } + + fn error() -> ReadResult { + ReadResult::Error() + } +} + +impl Encoder for ReadResult { + fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { + match self { + ReadResult::Ok(frames) => (atoms::ok(), frames).encode(env), + ReadResult::Error() => (atoms::error(), atoms::file_open_error()).encode(env), + } + } +} + +enum WriteResult { + Ok(), + Error(rustler::Atom), +} + +impl WriteResult { + fn ok() -> WriteResult { + WriteResult::Ok() + } + + fn error(reason: rustler::Atom) -> WriteResult { + WriteResult::Error(reason) + } +} + +impl Encoder for WriteResult { + fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { + match self { + WriteResult::Ok() => atoms::ok().encode(env), + WriteResult::Error(reason) => (atoms::error(), reason).encode(env), + } + } +} +#[rustler::nif(name = "get_major_frames")] +fn major_frames(path: String) -> ReadResult { match Tag::read_from_path(path) { Ok(tag) => { let frames = MajorFrames { @@ -60,28 +98,26 @@ fn major_frames<'a>(env: Env<'a>, args: &[Term<'a>]) -> NifResult> { year: tag.year(), date_recorded: tag.date_recorded().map(NaiveDateTime::from), date_released: tag.date_released().map(NaiveDateTime::from), - artist: tag.artist(), - album: tag.album(), - album_artist: tag.album_artist(), - title: tag.title(), + artist: tag.artist().map(|s| s.to_string()), + album: tag.album().map(|s| s.to_string()), + album_artist: tag.album_artist().map(|s| s.to_string()), + title: tag.title().map(|s| s.to_string()), duration: tag.duration(), - genre: tag.genre(), + genre: tag.genre().map(|s| s.to_string()), disc: tag.disc(), total_discs: tag.total_discs(), track: tag.track(), total_tracks: tag.total_tracks(), pictures: tag.pictures().map(ID3Picture::from).collect::>(), }; - Ok((atoms::ok(), frames).encode(env)) + ReadResult::ok(frames) } - Err(_e) => Ok((atoms::error(), atoms::file_open_error()).encode(env)), + Err(_e) => ReadResult::error(), } } -fn write_major_frames<'a>(env: Env<'a>, args: &[Term<'a>]) -> NifResult> { - let frames: MajorFrames = args[0].decode()?; - let path: String = args[1].decode()?; - +#[rustler::nif] +fn write_major_frames<'a>(frames: MajorFrames, path: String) -> WriteResult { match Tag::read_from_path(&path) { Ok(tag) => { let mut tag = tag; @@ -140,11 +176,11 @@ fn write_major_frames<'a>(env: Env<'a>, args: &[Term<'a>]) -> NifResult set_pictures(&mut tag, frames.pictures); match tag.write_to_path(&path, Version::Id3v24) { - Ok(_) => Ok(atoms::ok().encode(env)), - Err(_) => Ok((atoms::error(), atoms::tag_write_error()).encode(env)), + Ok(_) => WriteResult::ok(), + Err(_) => WriteResult::error(atoms::tag_write_error()), } } - Err(_e) => Ok((atoms::error(), atoms::file_open_error()).encode(env)), + Err(_e) => WriteResult::error(atoms::file_open_error()), } } diff --git a/native/id3/src/nif_converter/datetime.rs b/native/id3/src/nif_converter/datetime.rs index 6d530d5..793eb22 100644 --- a/native/id3/src/nif_converter/datetime.rs +++ b/native/id3/src/nif_converter/datetime.rs @@ -3,12 +3,12 @@ use rustler::types::atom::Atom as NifAtom; use rustler::NifStruct; mod atoms { - use rustler::rustler_atoms; + use rustler::atoms; - rustler_atoms! { - atom ok; - atom error; - atom calendar_iso = "Elixir.Calendar.ISO"; + atoms! { + ok, + error, + calendar_iso = "Elixir.Calendar.ISO", } } diff --git a/native/id3/src/nif_converter/picture.rs b/native/id3/src/nif_converter/picture.rs index d84ba1b..f760648 100644 --- a/native/id3/src/nif_converter/picture.rs +++ b/native/id3/src/nif_converter/picture.rs @@ -4,40 +4,40 @@ use rustler::types::atom::Atom as NifAtom; use rustler::NifStruct; mod atoms { - use rustler::rustler_atoms; + use rustler::atoms; - rustler_atoms! { - atom ok; - atom error; + atoms! { + ok, + error, } } #[allow(non_snake_case)] mod pictype_atoms { - use rustler::rustler_atoms; + use rustler::atoms; - rustler_atoms! { - atom Other; - atom Icon; - atom OtherIcon; - atom CoverFront; - atom CoverBack; - atom Leaflet; - atom Media; - atom LeadArtist; - atom Artist; - atom Conductor; - atom Band; - atom Composer; - atom Lyricist; - atom RecordingLocation; - atom DuringRecording; - atom DuringPerformance; - atom ScreenCapture; - atom BrightFish; - atom Illustration; - atom BandLogo; - atom PublisherLogo; + atoms! { + Other, + Icon, + OtherIcon, + CoverFront, + CoverBack, + Leaflet, + Media, + LeadArtist, + Artist, + Conductor, + Band, + Composer, + Lyricist, + RecordingLocation, + DuringRecording, + DuringPerformance, + ScreenCapture, + BrightFish, + Illustration, + BandLogo, + PublisherLogo, } }