Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but you can also compare across forks.

...
  • 7 commits
  • 7 files changed
  • 0 commit comments
  • 2 contributors
1  .gitignore
View
@@ -1 +1,2 @@
*.beam
+ebin/*.app
2  CONTRIBUTORS
View
@@ -0,0 +1,2 @@
+Per Andersson <avtobiff@gmail.com>
+Bip Thelin <bip@thelin.se>
2  Makefile
View
@@ -27,7 +27,7 @@ dialyzer:
test:
erlc -W +debug_info +compressed +strip -o test/ test/*.erl
- erl -noshell -pa ebin -pa test -eval "uuid_v4_tests:test()" -eval "init:stop()"
+ erl -noshell -pa ebin -pa test -eval "uuid_tests:test()" -eval "init:stop()"
install: build
# create dist directory and install files
22 README
View
@@ -1,8 +1,10 @@
ERLANG UUID
===========
-This module implements UUID v4, UUID generated by a (pseudo) random number
-generator.
+This module implements UUID v4 and v5 as of RFC 4122.
+
+UUID v4 return a UUID generated by a (pseudo) random number generator.
+UUID v5 return a UUID generated using SHA1 and a given name within a namespace.
Source tracking available at
@@ -28,6 +30,10 @@ Install to different $ERL_ROOT ($PREFIX/lib/erlang) by setting PREFIX
sudo make PREFIX=/opt/erlang install
+Include in your own project using Rebar. Add this to your rebar.config
+
+ {uuid, ".*",
+ {git, "git://gitorious.org/avtobiff/erlang-uuid.git", "master"}}
USE
@@ -36,7 +42,17 @@ Example of usage
1> uuid:to_string(uuid:uuid4()).
"79f492f8-1337-4200-abcd-92bada1cacao"
+ 2> uuid:to_string(uuid:uuid5(dns, "fqdn.example.com")).
+ "8fd7fa87-4c20-5809-a1b0-e07f5c224f02"
+ 3> uuid:to_string(uuid:uuid5(uuid:uuid4(), "my name")).
+ "6ff58b11-e0b2-536c-b6be-bdccd38836a2"
+
+UUID v5
+-------
+UUID v5 uses SHA1 to generate a UUID using a name and a namespace as
+initializer. Valid namespaces are the atoms: url, dns, oid, x500, nil or using
+a generated UUID either as a binary or as a UUID string representation.
- Per Andersson <avtobiff@gmail.com> Mon, 14 Feb 2011 11:51:30 +0100
+ Per Andersson <avtobiff@gmail.com> Sat, 18 Feb 2012 00:19:41 +0100
72 src/uuid.erl
View
@@ -19,13 +19,14 @@
%% @doc
%% Erlang UUID
%%
-%% Currently implements UUID v4, UUID generated with (pseudo) random number
-%% generator.
+%% Currently implements UUID v4 and v5 as of RFC 4122.
%%
%% Example usage
%% <pre>
%% 1> uuid:to_string(uuid:uuid4()).
%% "79f492f8-1337-4200-abcd-92bada1cacao"
+%% 2> uuid:to_string(uuid:uuid5(dns, "fqdn.example.com")).
+%% "8fd7fa87-4c20-5809-a1b0-e07f5c224f02"
%% </pre>
%% @end
%% -----------------------------------------------------------------------------
@@ -33,12 +34,12 @@
-module(uuid).
-author('Per Andersson').
--export([uuid4/0, to_string/1, to_binary/1]).
+-export([uuid4/0, uuid5/2, to_string/1, to_string/2, to_binary/1]).
%% @doc Create a UUID v4 (random) as a binary
-%% @spec () -> binary()
+-spec uuid4() -> binary().
uuid4() ->
{A1, A2, A3} = now(),
random:seed(A1, A2, A3),
@@ -50,24 +51,69 @@ uuid4() ->
uuid4(U0, U1, U2).
+%% @doc Create a UUID v5 (name based) as a binary.
+%% Magic numbers are from Appendix C of the RFC 4122.
+-spec uuid5(NamespaceOrUuid::atom() | string() | binary(),
+ Name::string()) -> binary().
+uuid5(dns, Name) ->
+ uuid5(list_to_binary([<<16#6ba7b8109dad11d180b400c04fd430c8:128>>, Name]));
+uuid5(url, Name) ->
+ uuid5(list_to_binary([<<16#6ba7b8119dad11d180b400c04fd430c8:128>>, Name]));
+uuid5(oid, Name) ->
+ uuid5(list_to_binary([<<16#6ba7b8129dad11d180b400c04fd430c8:128>>, Name]));
+uuid5(x500, Name) ->
+ uuid5(list_to_binary([<<16#6ba7b8149dad11d180b400c04fd430c8:128>>, Name]));
+uuid5(nil, Name) ->
+ uuid5(list_to_binary([<<0:128>>, Name]));
+uuid5(UuidStr, Name) when is_list(UuidStr) ->
+ uuid5(list_to_binary([to_binary(UuidStr), Name]));
+uuid5(UuidBin, Name) when is_binary(UuidBin) ->
+ uuid5(list_to_binary([UuidBin, Name]));
+uuid5(_, _) ->
+ erlang:error(badarg).
+
+
%% @private
+%% @doc Create a UUID v5 (name based) from binary
+-spec uuid5(Data::binary()) -> binary().
+uuid5(Data) ->
+ <<Sha1:128, _:32>> = crypto:sha(Data),
+
+ <<TimeLow:32, TimeMid:16, _AndVersion:4, TimeHi:12,
+ _AndReserved:2, ClockSeqHi:6, ClockSeqLow:8, Node:48>> = <<Sha1:128>>,
+
+ Version = 5,
+ Variant = 2#10,
+
+ <<TimeLow:32, TimeMid:16, Version:4, TimeHi:12,
+ Variant:2, ClockSeqHi:6, ClockSeqLow:8, Node:48>>.
+
+
%% @doc Create a 128 bit binary (UUID v4) from input
-%% @spec (U0, U1, U2) -> binary()
-%% where U0 = U1 = U2 = integer()
+-spec uuid4(U0::integer(), U1::integer(), U2::integer()) -> binary().
uuid4(U0, U1, U2) -> <<U0:48, 4:4, U1:12, 10:4, U2:60>>.
-%% @doc Format uuid string from binary
-%% @spec (Uuid::binary()) -> string()
-to_string(<<U0:32, U1:16, U2:16, U3:16, U4:48>>) ->
+%% @doc Format UUID string from binary
+-spec to_string(Uuid::binary()) -> string().
+to_string(Uuid) when is_binary(Uuid) ->
+ to_string(pretty, Uuid);
+to_string(_) ->
+ erlang:error(badarg).
+
+-spec to_string(simple | pretty, Uuid::binary()) -> string().
+to_string(pretty, <<U0:32, U1:16, U2:16, U3:16, U4:48>>) ->
lists:flatten(io_lib:format(
"~8.16.0b-~4.16.0b-~4.16.0b-~4.16.0b-~12.16.0b",
[U0, U1, U2, U3, U4]));
-to_string(_) ->
+to_string(simple, <<S:128>>) ->
+ lists:flatten(io_lib:format("~32.16.0b", [S]));
+to_string(_, _) ->
erlang:error(badarg).
+
%% @doc Format uuid binary from string
-%% @spec (UuidStr::string()) -> binary()
+-spec to_binary(UuidStr::string()) -> binary().
to_binary(UuidStr) when is_list(UuidStr) ->
Parts = string:tokens(UuidStr, "$-"),
[I0, I1, I2, I3, I4] = [hex_to_int(Part) || Part <- Parts],
@@ -75,6 +121,10 @@ to_binary(UuidStr) when is_list(UuidStr) ->
to_binary(_) ->
erlang:error(badarg).
+
+%% @private
+%% @doc Convert from hexadecimal digit represented as string to decimal.
+-spec hex_to_int(Hex::string()) -> integer().
hex_to_int(Hex) ->
{ok, [D], []} = io_lib:fread("~16u", Hex),
D.
99 test/uuid_tests.erl
View
@@ -0,0 +1,99 @@
+%% -----------------------------------------------------------------------------
+%% Copyright © 2010 Per Andersson
+%%
+%% Erlang UUID is free software: you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation, either version 3 of the License, or
+%% (at your option) any later version.
+%%
+%% Erlang UUID is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with erlang-uuid. If not, see <http://www.gnu.org/licenses/>.
+%% -----------------------------------------------------------------------------
+%% @author Per Andersson <avtobiff@gmail.com>
+%% @copyright 2010 Per Andersson
+%% @doc
+%% Erlang UUID
+%%
+%% HERE BE UUID TESTS
+%% @end
+%% -----------------------------------------------------------------------------
+
+-module(uuid_tests).
+-author('Per Andersson').
+
+-include_lib("eunit/include/eunit.hrl").
+
+
+uuid_binary_test() ->
+ Uuid = uuid:uuid4(),
+
+ ?assertMatch(<<_U0:48, 4:4, _U1:12, 10:4, _U2:60>>, uuid:uuid4()),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(dns, "fqdn.example.com")),
+ ?assertEqual(uuid:uuid5(dns, "fqdn.example.com"),
+ uuid:uuid5(dns, "fqdn.example.com")),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(oid, "2.5.6")),
+ ?assertEqual(uuid:uuid5(oid, "2.5.6"), uuid:uuid5(oid, "2.5.6")),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(url, "http://fqdn.example.com/path")),
+ ?assertEqual(uuid:uuid5(url, "http://fqdn.example.com/path"),
+ uuid:uuid5(url, "http://fqdn.example.com/path")),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(x500, "cn=John Doe, o=Acme, Inc., c=US")),
+ ?assertEqual(uuid:uuid5(x500, "cn=John Doe, o=Acme, Inc., c=US"),
+ uuid:uuid5(x500, "cn=John Doe, o=Acme, Inc., c=US")),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(nil, "my own unique name")),
+ ?assertEqual(uuid:uuid5(nil, "my own unique name"),
+ uuid:uuid5(nil, "my own unique name")),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(Uuid, "fqdn.example.com")),
+ ?assertEqual(uuid:uuid5(Uuid, "fqdn.example.com"),
+ uuid:uuid5(Uuid, "fqdn.example.com")),
+
+ ?assertMatch(<<_U0:48, 5:4, _U1:12, _:2, _U2:62>>,
+ uuid:uuid5(uuid:to_string(Uuid), "fqdn.example.com")),
+ ?assertEqual(uuid:uuid5(uuid:to_string(Uuid), "fqdn.example.com"),
+ uuid:uuid5(uuid:to_string(Uuid), "fqdn.example.com")).
+
+representation_test() ->
+ Uuid4 = uuid:uuid4(),
+ Uuid5 = uuid:uuid5(dns, "fqdn.example.com"),
+ ?assertMatch(Uuid4, uuid:to_binary(uuid:to_string(Uuid4))),
+ ?assertMatch(Uuid5, uuid:to_binary(uuid:to_string(Uuid5))).
+
+tostring_test() ->
+ SimpleUuid = "8fd7fa874c205809a1b0e07f5c224f02",
+ PrettyUuid = "8fd7fa87-4c20-5809-a1b0-e07f5c224f02",
+ ?assertMatch(PrettyUuid,
+ uuid:to_string(uuid:uuid5(dns, "fqdn.example.com"))),
+ ?assertMatch(PrettyUuid,
+ uuid:to_string(pretty, uuid:uuid5(dns, "fqdn.example.com"))),
+ ?assertMatch(SimpleUuid,
+ uuid:to_string(simple, uuid:uuid5(dns, "fqdn.example.com"))).
+
+exceptions_test() ->
+ ?assertMatch(ok, try_badarg(to_binary, [0])),
+ ?assertMatch(ok, try_badarg(to_string, [0])),
+ ?assertMatch(ok, try_badarg(to_string, [0, 0])),
+ ?assertMatch(ok, try_badarg(uuid5, [0, 0])).
+
+
+try_badarg(F, A) ->
+ try
+ apply(uuid, F, A)
+ catch error:badarg ->
+ ok
+ end.
49 test/uuid_v4_tests.erl
View
@@ -1,49 +0,0 @@
-%% -----------------------------------------------------------------------------
-%% Copyright © 2010 Per Andersson
-%%
-%% Erlang UUID is free software: you can redistribute it and/or modify
-%% it under the terms of the GNU General Public License as published by
-%% the Free Software Foundation, either version 3 of the License, or
-%% (at your option) any later version.
-%%
-%% Erlang UUID is distributed in the hope that it will be useful,
-%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-%% GNU General Public License for more details.
-%%
-%% You should have received a copy of the GNU General Public License
-%% along with erlang-uuid. If not, see <http://www.gnu.org/licenses/>.
-%% -----------------------------------------------------------------------------
-%% @author Per Andersson <avtobiff@gmail.com>
-%% @copyright 2010 Per Andersson
-%% @doc
-%% Erlang UUID
-%%
-%% HERE BE UUIDv4 TESTS
-%% @end
-%% -----------------------------------------------------------------------------
-
--module(uuid_v4_tests).
--author('Per Andersson').
-
--include_lib("eunit/include/eunit.hrl").
-
-
-uuid_v4_binary_test() ->
- ?assertMatch(<<_U0:48, 4:4, _U1:12, 10:4, _U2:60>>, uuid:uuid4()).
-
-representation_test() ->
- Uuid = uuid:uuid4(),
- ?assertMatch(Uuid, uuid:to_binary(uuid:to_string(Uuid))).
-
-exceptions_test() ->
- ?assertMatch(ok, try_badarg(to_binary, 0)),
- ?assertMatch(ok, try_badarg(to_string, 0)).
-
-
-try_badarg(F, A) ->
- try
- uuid:F(A)
- catch error:badarg ->
- ok
- end.

No commit comments for this range

Something went wrong with that request. Please try again.